编程 百度 Unlimited OCR 深度实战:30亿参数仅激活5亿、R-SWA注意力革命——长文档OCR端到端SOTA完全指南(2026)

2026-06-28 06:43:54 +0800 CST views 12

百度 Unlimited OCR 深度实战:30亿参数仅激活5亿、R-SWA注意力革命——长文档OCR端到端SOTA完全指南(2026)

作者按:2026年6月22日,百度开源发布了 Unlimited OCR 模型,总参数量30亿,推理时仅激活5亿参数,在 OmniDocBench v1.6 基准测试中拿下93.92%的综合成绩,直接刷新端到端 OCR 的 SOTA。更重要的是,它通过对 Reference Sliding Window Attention(R-SWA)的巧妙设计,把解码器的 KV cache 从线性增长压成了常数——这意味着"一次前向推理转录几十页文档"不再是梦话,而是可以 run 起来的真实代码。


目录

  1. 背景介绍:OCR 的长文档困境与端到端革命
  2. 核心概念:Unlimited OCR 架构设计与 R-SWA 机制深度解析
  3. 架构分析:从 DeepEncoder 到 MoE 解码器的完整技术栈
  4. 代码实战:环境搭建、SGLang 部署与 Python API 全栈实战
  5. 性能优化:KV Cache 压缩、推理加速与生产级调优
  6. 总结与展望:长文档 OCR 的时代来了

1. 背景介绍:OCR 的长文档困境与端到端革命

1.1 传统 OCR 的两阶段之痛

OCR(Optical Character Recognition,光学字符识别)技术发展到今天,已经走过了半个多世纪的路程。从最早的模式匹配、到机器学习分类器、再到深度学习时代的神经网络,OCR 的精度和提升一直未曾停止。

然而,传统 OCR 系统始终面临一个根本性的架构问题:两阶段流水线

典型的传统 OCR 流程是这样的:

输入图像
    ↓
[阶段一:文本检测] → 检测出图像中的文字区域(文本框、文本行、单词边界)
    ↓
[阶段二:文本识别] → 对每个检测到的文本区域分别进行字符识别
    ↓
输出文本序列

这个架构在理论上没什么问题,甚至在很多场景下表现还不错。但当你把它放到长文档解析的场景里,问题就一个个冒出来了:

问题一:误差累积。 检测阶段的误差会直接传递到识别阶段。如果检测框偏了、漏了、或者把两个单词框在了一起,识别结果必然受影响。两个阶段的误差是"串联"的,整体精度上限被锁死在 精度_检测 × 精度_识别

问题二:计算冗余。 检测和识别是两个独立的模型,各自需要单独的前向推理。对于几十页甚至上百页的长文档,这个"各自为政"的计算方式意味着大量的重复计算和显存浪费。

问题三:上下文割裂。 传统 OCR 是"逐框识别"的,每个文本区域是独立处理的,模型看不到全局上下文。遇到模糊、遮挡、字体特殊的情况,单靠一个小小的文本区域,识别率自然上不去。

问题四:长文档的"记忆力"瓶颈。 这是最核心的问题。当文档从一页变成十页、百页,模型需要"记住"前面页面的内容来辅助后续识别(比如一致的术语、格式、排版风格)。但传统的两阶段架构根本没有设计"跨页记忆"的能力,只能 for-loop 一页一页地跑,前面的内容识别完就扔掉了,后面的识别完全从头开始。

1.2 端到端 OCR:把检测和识别融进一个模型

端到端 OCR(End-to-End OCR)的核心思路非常直接:抛弃两阶段流水线,用一个统一的神经网络架构,直接从输入图像映射到输出文本序列

这听起来像是把两个模型"拼"在一起,但实际上端到端 OCR 做的是更激进的事——它重新设计了整个信息流:

输入图像(整页/多页)
    ↓
[统一的编码器-解码器架构]
    ↓
输出文本序列(完整文档)

端到端 OCR 的优势:

  1. 信息无损传递。 检测和识别在一个模型里完成,中间表示是连续的可微张量,不存在"检测框坐标"这种离散传递,信息上限更高。

  2. 全局上下文建模。 端到端模型可以同时"看到"整个页面的布局、多列的排版、跨页的连续性,识别准确率天然更高。

  3. 计算效率提升。 一次前向推理完成全部工作,避免了两阶段各自的独立推理开销。

  4. 端到端可微优化。 整个 pipeline 可以从最终的文本输出直接反向传播优化,不需要分别标注"检测框"和"识别标签"两种监督信号。

但是,端到端 OCR 有一个致命的短板:当文档变长时,计算复杂度和显存消耗会线性爆炸

为什么?因为端到端 OCR 通常基于 Transformer 架构(编码器-解码器),而 Transformer 的解码器在自回归生成文本时,需要维护一个随生成长度线性增长的 KV cache(Key-Value cache)。

具体来说:

  • 生成第 1 个 token:KV cache 大小 = 1 个 token 的 K/V 张量
  • 生成第 10 个 token:KV cache 大小 = 10 个 token 的 K/V 张量
  • 生成第 T 个 token:KV cache 大小 = T 个 token 的 K/V 张量

当 T 达到几千甚至几万(长文档的完整文本序列),KV cache 占用的显存和带来的计算开销会让推理直接 OOM(Out of Memory)。

这就是长文档 OCR 的核心矛盾:端到端架构在精度上碾压两阶段,但显存和计算的线性增长让它无法处理真实场景下的长文档。

1.3 DeepSeek OCR 的突破与未竟之业

2025年末,DeepSeek 团队发布了 DeepSeek-OCR,首次把一个大规模 MoE(Mixture-of-Experts)架构成功应用于端到端 OCR,在多个基准测试上取得了令人瞩目的成绩。

DeepSeek-OCR 的核心架构设计是:

  • DeepEncoder:多层的视觉编码器,负责从输入图像中提取丰富的视觉特征
  • MoE 解码器:解码器采用 MoE 结构,每个 FFN(Feed-Forward Network)层替换成多个"专家"网络,每次推理只激活其中的少数几个专家

MoE 架构的引入是一个关键创新:它让模型在保持庞大总参数量(承载更多知识和能力)的同时,把每次推理的实际计算量控制在可接受的范围内(只激活少数专家)。

但 DeepSeek-OCR 仍然没有解决长文档的核心问题:当文档长度增加时,解码器的 KV cache 仍然在线性增长。你可以把一个 3 页的文档跑通,但面对 30 页、300 页的文档时,显存墙依然在那里。

这正是百度 Unlimited OCR 要解决的问题。

1.4 Unlimited OCR:让"一次前向推理处理几十页文档"成为现实

百度于 2026 年 6 月 22 日开源发布的 Unlimited OCR,在 DeepSeek-OCR 架构的基础上,针对长文档场景做了根本性的架构改造。

核心数据先看:

  • 总参数量:30 亿(3B)
  • 推理时激活参数:仅约 5 亿(500M-570M)
  • OmniDocBench v1.6 综合得分:93.92%(端到端 SOTA)
  • 上下文长度:32K tokens
  • 核心创新:Reference Sliding Window Attention(R-SWA)

Unlimited OCR 能做到什么?

把一个 1024×1024 的 PDF 页面图像压缩为仅 256 个视觉 token,然后把几十页这样的文档拼接在一起,一次性送入模型做端到端推理——整个过程只需要一次前向传播,不需要 for-loop 逐页处理,不需要外部调度器拼接结果

这意味着什么?意味着 OCR 长文档处理从"逐页扫描式"进化到了"一次性全景式"。

在人类看来,这是很自然的事:你瞄几眼刚写过的字,然后继续往下写,几百页下来节奏稳定。但在此之前的机器 OCR 系统,根本没有这种"持续注意力"的能力。

Unlimited OCR 通过 R-SWA 机制,把解码器的 KV cache 从"随生成长度线性增长"压成了"常数"——这是本文最核心的技术亮点,我们在第二章会完全拆解它的原理。


2. 核心概念:Unlimited OCR 架构设计与 R-SWA 机制深度解析

2.1 模型整体架构

Unlimited OCR 的架构延续并改进了 DeepSeek-OCR 的设计,整体可以分为两大部分:

输入:多页文档图像(1024×1024 × N页)
    ↓
[DeepEncoder:两级视觉编码 + 16× Token 压缩]
    ↓
视觉 Token 序列(每页 256 个 token)
    ↓
[MoE 解码器 + R-SWA 注意力]
    ↓
输出:完整文档的文本序列(最长 32K tokens)

2.1.1 DeepEncoder:两级视觉编码

DeepEncoder 负责把原始的文档图像转换成模型可以处理的 token 序列。它采用两级视觉编码策略:

第一级:高分辨率局部特征提取

用高分辨率的视觉编码器(通常是基于 CNN 或 Vision Transformer 的架构)对输入图像进行逐 patch 的特征提取。这一级的目标是保留图像中的细粒度视觉信息——比如小字号文字的笔画、特殊符号的形状、表格线的走向。

对于 1024×1024 的输入图像,第一级编码器通常会把它切分成若干个 patch(比如 32×32 或 16×16),每个 patch 提取一个视觉特征向量。这样一来,1024×1024 的图像就会产生数百个甚至上千个初级视觉 token。

第二级:低分辨率全局语义压缩

第一级产生的初级视觉 token 数量太多了(1024×1024 图像可能产生 1024~4096 个 token),如果直接送给解码器,上下文长度会爆炸。

所以第二级编码器的作用是对第一级的输出进行语义压缩:通过一个轻量级的 Transformer 或 CNN 网络,把空间上相邻的初级视觉 token 聚合起来,最终把 1024×1024 的图像压缩成仅 256 个视觉 token

压缩比是多少?1024×1024 的像素空间 → 256 个 token,相当于每个 token "负责" 4096 个像素的信息。这就是所谓的 16× token 压缩(如果你从 patch 数量的角度算,压缩比可能更高)。

为什么这个压缩是可行的? 因为文档图像有很强的结构性和冗余性。大片的空白、重复的字体、规律的排版——这些信息不需要每个像素都保留一个独立的 token,完全可以通过智能的压缩策略,"用最少的 token 表达最完整的视觉语义"。

2.1.2 MoE 解码器:总参数 30B,激活仅 5B

解码器的任务是根据 DeepEncoder 产生的视觉 token 序列,自回归地生成文本序列(OCR 的识别结果)。

Unlimited OCR 的解码器采用了 MoE(Mixture-of-Experts)架构,这是让"大模型"和"快推理"同时成立的关键技术。

MoE 的基本思想:

传统 Transformer 解码器的每一层有一个 FFN(Feed-Forward Network),每次推理时这个 FFN 的全部参数都要参与计算。

MoE 的做法是:把这一个 FFN 替换成 N 个"专家"FFN(比如 N=8 或 N=16),每次推理时,一个"路由网络"(Router/Gating Network)根据当前 token 的特征,动态地选择其中 K 个专家(比如 K=2)来参与计算。

传统 FFN:
输入 token → [FFN(全部参数)] → 输出

MoE FFN:
输入 token → [Router 选择 Top-K 专家] → [Expert_1 + Expert_2 + ... + Expert_K] → 输出
              (每次只激活 K 个,K << N)

MoE 的效果:

  • 总参数量可以做得很大(因为大部分专家在大多数时候是"沉睡"的)
  • 每次推理的实际计算量只取决于激活的专家数量,而不是总参数
  • 不同的专家可以"分工":有的专家专门处理英文、有的专门处理中文、有的专门处理代码、有的专门处理数学公式

Unlimited OCR 的总参数量是 30 亿(3B),但每次推理时只激活约 5 亿(500M-570M)参数。这意味着它的推理成本和一个"原生 5B"的密集模型差不多,但能力上限远高于后者。

2.1.3 问题:长文档让 KV Cache 线性爆炸

好,现在到了最核心的问题。

MoE 解决了"模型大、计算慢"的问题,但还有一个问题它没解决:自回归生成时的 KV cache 增长问题

Transformer 解码器在生成文本时是自回归的(autoregressive):

第1步:输入视觉token → 生成第1个输出token "今"
第2步:输入视觉token + "今" → 生成第2个输出token "天"
第3步:输入视觉token + "今" + "天" → 生成第3个输出token "..."
...
第T步:输入视觉token + "今" + "天" + ... + "第T-1个token" → 生成第T个token

在每一步,解码器需要对"已经生成的所有 token"计算 Key 和 Value 张量(这就是 KV cache 的由来),以便在 Self-Attention 中计算当前 token 对所有历史 token 的注意力权重。

问题来了: 当生成长度 T 增加时,KV cache 的大小是 O(T) 线性增长的。

对于短文档(T < 1000),这个问题不大。但对于长文档(T 可能达到 10000、32000),KV cache 占用的显存会让推理直接崩溃。

更糟糕的是,OCR 任务的特殊性让这个问题更严峻:

  • 视觉 token 序列本身就已经占了一批 KV cache(对应编码器输出)
  • 生成的文本 token 又在不断追加新的 KV cache
  • 两者加在一起,长文档场景下显存压力是"双倍"的

2.2 R-SWA:把 KV Cache 从线性增长压成常数

Unlimited OCR 的核心创新,就是用 Reference Sliding Window Attention(R-SWA,参考滑动窗口注意力) 替换了解码器中的标准 Self-Attention 机制。

R-SWA 的设计灵感来源:

人类在抄书或长文写作时,并不是把前面所有写过的内容都"记在脑子里"。人类的策略是:

  1. 对于已经写过的内容,不需要逐字记住,只需要记住"关键点"(参考信息)
  2. 对于正在写的内容,需要看到"最近写过的一小段"(局部上下文),保持连贯性

R-SWA 把这套策略翻译成了注意力机制的数学形式。

2.2.1 R-SWA 的数学定义

在标准 Self-Attention 中,生成第 t 个 token 时,注意力权重是这样计算的:

Attention(Q_t, K_{1..t}, V_{1..t}) = softmax(Q_t @ K_{1..t}^T / sqrt(d)) @ V_{1..t}

这里 K_{1..t}V_{1..t}所有历史 token(1 到 t)的 K/V 张量,随着 t 增大,这个张量越来越长。

R-SWA 做了两个关键改动:

改动一:Reference Tokens(参考 Token)—— 全部可见

把视觉编码器输出的 token 序列定义为"Reference Tokens"(记为 R),在生成每个新 token 时,R-SWA 允许当前 token 看到全部 R

这意味着什么?意味着模型在生成任何位置的文本时,都可以随时"回头看"原始的视觉图像特征——这保证了 OCR 的识别精度不会因"遗忘图像"而下降。

改动二:Sliding Window(滑动窗口)—— 只看最近 n 个

对于已经生成的文本 token 序列(记为 y_1, y_2, ..., y_{t-1}),R-SWA 不保留全部历史,而是只保留最近 n 个 token 的 KV cache(默认 n=128)。

生成第 t 个 token 时,R-SWA 看到的 KV cache:
- 全部 Reference Tokens(R):视觉特征,恒定大小,不随 t 增长
- 最近 n 个输出 Tokens(y_{t-n}, ..., y_{t-1}):局部上下文,大小恒定 = n

总 KV cache 大小 = |R| + n = 常数!

这就是 R-SWA 的核心魔力:不管生成多长的文本,KV cache 的大小始终是一个常数(等于视觉 token 数量 + 滑动窗口大小)。

2.2.2 为什么"只看最近 128 个 token"不会影响长文档质量?

你可能会问:只看最近 128 个 token,那更早的内容不就"忘"了吗?对于长文档 OCR,这会影响质量吗?

答案是:不会,因为 OCR 任务的特殊性。

OCR 是"感知→转录"任务,而不是"理解→生成"任务。在 OCR 中:

  • 模型的主要依据是视觉图像(Reference Tokens),而不是前面生成的文本
  • 前面生成的文本主要起"语言模型"的作用:保证识别出的文字符合语言规律(比如中文的语法、英文的拼写)
  • 而这种"语言模型"能力,实际上只需要局部上下文(最近几个词、最近一两句话)就足够了

举个例子:

  • 你看到图片上有一个模糊的字,你需要根据"前面的文字"来推断这个字是什么——但你只需要看"前面几个字"就够了,不需要看"前面几页"
  • 比如"...今天天气很___",你根据"很"字就能推断下一个字可能是"好"、"热"、"冷"等,而不需要把整篇文章都记住

当然,对于某些特殊场景(比如跨页的表格续接、多页文档的术语一致性),128 的窗口可能确实不够。这也是为什么 Unlimited OCR 提供了可配置的 n 值,你可以根据实际场景调整滑动窗口的大小。

2.2.3 R-SWA 的计算复杂度分析

让我们定量地看一下 R-SWA 带来的计算收益。

标准 Self-Attention 的 KV cache 复杂度:

每生成一个新 token:
- KV cache 大小 = O(T) (T 是当前已生成的 token 数)
- Attention 计算复杂度 = O(T × d) (d 是特征维度)
- 生成 T 个 token 的总计算量 = O(T² × d)

R-SWA 的 KV cache 复杂度:

每生成一个新 token:
- KV cache 大小 = O(|R| + n) = O(常数)
- Attention 计算复杂度 = O((|R| + n) × d) = O(常数 × d)
- 生成 T 个 token 的总计算量 = O(T × (|R| + n) × d) = O(T)

从 O(T²) 降到 O(T)——这是量级上的跨越。

更重要的是显存的节省。在 Unlimited OCR 的实践中,R-SWA 把 32K 上下文场景下的 KV cache 显存占用从数十 GB 压到了不足 1GB

这也是为什么 Unlimited OCR 能够"单次前向推理处理几十页文档"——不是因为模型变小了,而是因为 R-SWA 把长序列推理的显存瓶颈给拆了。


3. 架构分析:从 DeepEncoder 到 MoE 解码器的完整技术栈

3.1 视觉编码管线的完整数据流

让我们跟随着一张 1024×1024 的文档图像,完整地走一遍 Unlimited OCR 的数据流。

3.1.1 输入预处理:图像归一化与分块策略

原始输入:PIL Image 或 NumPy Array,尺寸 1024×1024×3(RGB)
    ↓
[预处理]
    - Resize(如果输入尺寸不同)
    - Normalize(像素值归一化到 [0, 1] 或 [-1, 1])
    - 可选:对比度增强、去噪、二值化(针对扫描质量差的文档)
    ↓
Tensor:shape = [1, 3, 1024, 1024](batch_size=1, RGB, H, W)

多页文档的处理方式:

对于多页文档,Unlimited OCR 支持两种输入模式:

  1. 拼接模式:把多页图像在垂直方向上拼接成一张"长图",然后作为单张图像输入。适用于页数不多(比如 <10 页)的场景。

  2. Batch 模式:把多页图像组成一个 batch,并行编码。适用于批量处理大量文档的场景。

无论哪种模式,DeepEncoder 都会把每一页压缩成 256 个视觉 token。所以 N 页文档最终会产生 N × 256 个视觉 token。

3.1.2 第一级编码:高分辨率局部特征提取

第一级编码器通常基于 ViT(Vision Transformer)CNN+Transformer 混合架构

以 ViT 为例:

输入图像 Tensor [1, 3, 1024, 1024]
    ↓
[Patch Embedding]
    - 把图像切分成 P×P 的 patch(比如 P=32,则产生 (1024/32)×(1024/32) = 1024 个 patch)
    - 每个 patch 通过一个可学习的线性投影,映射为一个 D 维向量(比如 D=768)
    ↓
Patch Embeddings:[1, 1024, D]
    ↓
[可学习的位置编码(Positional Encoding)]
    - 给每个 patch 加上位置信息(因为 Transformer 本身不知道 patch 的空间位置)
    ↓
    + [CLS Token](可选,用于全局特征)
    ↓
[Transformer Encoder Layers(×N层)]
    - Multi-Head Self-Attention
    - FFN
    - Layer Norm + Residual
    ↓
输出:[1, 1024, D] 或 [1, 1025, D](含 CLS)

这一级输出的 1024 个 token,每个都包含了局部区域的精细视觉信息。对于 OCR 来说,这些局部信息非常重要——因为一个汉字、一个英文字母,本身就只需要很小的局部区域就能识别。

但问题是:1024 个 token 直接送给解码器,会让编码器的输出序列太长,增加解码器的计算负担。

所以需要第二级编码来做压缩。

3.1.3 第二级编码:语义压缩到 256 Token

第二级编码器的任务是把 1024 个初级视觉 token 压缩成 256 个"高级语义 token"。

常用压缩策略:

策略一:可学习的 Token 压缩(Learnable Token Compression)

这是最常见也最有效的策略。核心思路是:定义 256 个"可学习的查询向量"(Learnable Query Vectors),然后用 Cross-Attention 机制,让这 256 个查询向量去"关注"1024 个初级视觉 token,最终输出 256 个压缩后的视觉 token。

初级视觉 token(1024个) → [Cross-Attention] ← 可学习查询向量(256个)
                                           ↓
                              压缩后视觉 token(256个)

这个过程类似于 Perceiver / Perceiver IO 架构中的"潜在数组"(Latent Array)设计,也类似于 BLIP / BLIP-2 中的 Q-Former。

数学上,这可以写成:

Z_compressed = CrossAttention(Q=LearnableQueries[256], K=Z_primary[1024], V=Z_primary[1024])

其中 Z_primary 是第一级编码器的输出,Z_compressed 是压缩后的视觉 token 序列。

策略二:卷积下采样(Convolutional Downsampling)

把 1024 个 token 重新排列成 2D 空间网格(比如 32×32),然后通过卷积层(stride > 1)进行空间下采样,最终得到 16×16 = 256 个 token。

这个策略计算效率更高,但没有可学习的查询向量那么灵活。

策略三:Token 合并(Token Merging / ToMe)

通过度量 token 之间的相似度,把相似的 token "合并"成一个。比如用 K-Means 或图聚类算法,把 1024 个 token 聚类成 256 个中心。

Unlimited OCR 具体用的是哪种策略?根据公开的技术资料和模型配置,它采用的是策略一(可学习的 Token 压缩),因为这能最大化压缩质量——256 个查询向量可以通过训练"学会"如何最有效地从初级视觉 token 中提取 OCR 相关的语义信息。

3.1.4 压缩效果的定量分析

1024×1024 像素 → 256 个 token,相当于每个 token 覆盖约 4096 个像素

这个压缩比是否合理?我们可以做一个简单的估算:

  • 一个标准的中文汉字,在 1024×1024 的 A4 页面图像中,约占 20×20 = 400 像素
  • 4096 像素 ≈ 10 个汉字的视觉信息量
  • 也就是说,压缩后的每个 token "负责"约 10 个汉字的视觉特征

这个粒度对于 OCR 来说是完全足够的——因为模型不需要"逐像素"地记住每个汉字的笔画,只需要记住足够的语义特征来正确识别这个字,以及它与周围字的关系。

3.2 MoE 解码器的详细结构设计

现在让我们深入 MoE 解码器的内部。

3.2.1 解码器整体结构

Unlimited OCR 的解码器基于标准的 Transformer Decoder 架构,但做了以下关键改动:

输入:压缩后视觉 token 序列 [256 × N页]
    ↓
[Embedding Layer](如果视觉 token 和解码器不在同一特征空间)
    ↓
[Decoder Layer 1]
    - Multi-Head Cross-Attention(Q=文本token, K/V=视觉token)
    - R-SWA(替代标准的 Masked Self-Attention)
    - MoE FFN(替代标准 FFN)
    - Layer Norm + Residual
    ↓
[Decoder Layer 2]
    ...(同上)
    ↓
[Decoder Layer L]
    ↓
[输出投影层(LM Head)]
    ↓
输出:下一个 token 的概率分布

关键区别:

  • 标准 Transformer Decoder 的每一层有一个 Masked Self-Attention(用于文本 token 之间的注意力)
  • Unlimited OCR 把 Masked Self-Attention 替换成了 R-SWA
  • 标准 FFN 替换成了 MoE FFN

3.2.2 MoE FFN 的工作机制

每个 Decoder Layer 中的 MoE FFN:
    ↓
输入 token 特征 x [batch, seq_len, d_model]
    ↓
[Router / Gating Network]
    - 一个轻量级线性层:W_router ∈ R^{d_model × N_experts}
    - 计算路由分数:scores = x @ W_router → [batch, seq_len, N_experts]
    - 取 Top-K(比如 K=2):selected_experts = TopK(scores, k=2)
    - 计算权重归一化:weights = Softmax(scores[selected_experts])
    ↓
[Expert FFNs(N个,每次只激活K个)]
    - Expert_i(x) = FFN_i(x)  (第 i 个专家的前馈网络)
    - 输出 = Σ_{i ∈ selected_experts} weights[i] × Expert_i(x)
    ↓
输出:[batch, seq_len, d_model]

专家数量与激活数量的设计权衡:

  • N_experts 越大,模型的"容量"越大(可以存储更多专精的知识),但路由网络的计算开销也越大
  • K(激活数量)越小,推理越快,但模型表达能力可能受限

根据 Unlimited OCR 的模型配置(总参数 3B,激活 500M),可以推算出:

  • 如果 d_model = 2048,Decoder Layers = 24 层
  • 每层 MoE FFN 有 N_experts = 8 个专家
  • 每个专家的大小约为 d_model × d_ffn × 2(标准 FFN 的中间层维度通常是 d_model 的 2-4 倍)
  • 每次激活 K=2 个专家 → 激活参数约占总参数的 1/4 ~ 1/3

具体的架构超参数需要参考官方发布的模型配置文件(config.json),但以上推算可以作为理解 MoE 效率优势的理论框架。

3.2.3 负载均衡与专家 specialization

MoE 训练中的一个核心挑战是负载均衡(Load Balancing):如果路由网络总是把相同的 token 发送给相同的少数几个专家,那么其他专家就会"饿死"(得不到训练),MoE 的参数效率优势就丧失了。

Unlimited OCR 在训练时采用了标准的 MoE 负载均衡策略:

  1. 辅助损失(Auxiliary Loss / Load Balance Loss):在训练目标中增加一个额外的损失项,鼓励路由分布均匀。
Load_Balance_Loss = N_experts × Σ_{i=1}^{N_experts} (f_i × P_i)

其中 f_i 是第 i 个专家被分配到的 token 比例,P_i 是所有 token 选择第 i 个专家的平均概率。当负载均衡时,f_i ≈ 1/N_expertsP_i ≈ 1/N_experts,Loss 最小。

  1. 专家 Dropout / 随机路由:在训练初期,故意引入一定的随机性,防止路由网络过早地"锁定"在某些专家上。

  2. Expert Specialization 的正则化:通过可视化分析,观察不同专家是否真的学到了不同的"专业性"(比如有的专家擅长处理中文、有的擅长英文、有的擅长数字和公式)。

3.3 R-SWA 的实现细节

3.3.1 注意力掩码(Attention Mask)的设计

在标准 Self-Attention 中,因果掩码(Causal Mask)确保位置 t 的 token 只能注意到位置 ≤ t 的 token:

Mask[i, j] = 1 if j <= i else 0(或者 -inf 用于 softmax 前的屏蔽)

在 R-SWA 中,注意力掩码需要修改为:

对于位置 t 的 token:
    - 所有 Reference Token 位置(假设是 0..|R|-1):可见(Mask = 1)
    - 输出 token 位置中,最近 n 个(即 t-n .. t-1):可见
    - 其他输出 token 位置(即 0 .. t-n-1):不可见(Mask = 0 或 -inf)

这在代码实现上非常简单,只需要在标准的因果掩码基础上,"解锁"对 Reference Token 的全部访问权限。

3.3.2 KV Cache 的管理策略

在推理实现中,R-SWA 的 KV cache 管理比标准 Self-Attention 更简单:

标准 Self-Attention 的 KV cache 管理:

# 每生成一个新 token,需要把它的 K/V 追加到 cache 中
kv_cache_keys.append(K_new)    # K_new: [batch, 1, d_k]
kv_cache_values.append(V_new)   # V_new: [batch, 1, d_v]

# attention 计算时,需要把全部历史 K/V 拼接起来
K_full = concat(kv_cache_keys, dim=1)    # [batch, t, d_k]
V_full = concat(kv_cache_values, dim=1)  # [batch, t, d_v]

问题在于:concat 操作每次都要分配更大的显存,或者需要预分配一个超大显存池——无论哪种方式,显存占用都是 O(T) 增长的。

R-SWA 的 KV cache 管理:

# Reference Tokens 的 K/V:一次性计算,全程不变
K_ref = compute_K(reference_tokens)   # [batch, |R|, d_k]
V_ref = compute_V(reference_tokens)   # [batch, |R|, d_v]

# 输出 token 的 K/V:只保留一个固定大小的循环缓冲区(Circular Buffer)
kv_cache_keys_window = deque(maxlen=n)   # 只存最近 n 个
kv_cache_values_window = deque(maxlen=n)

# 每生成一个新 token:
kv_cache_keys_window.append(K_new)
kv_cache_values_window.append(V_new)

# attention 计算:
K_full = concat([K_ref] + list(kv_cache_keys_window), dim=1)
V_full = concat([V_ref] + list(kv_cache_values_window), dim=1)
# K_full 的长度 = |R| + min(t, n) <= |R| + n = 常数!

关键优化:用 deque(双端队列)作为循环缓冲区,当长度超过 n 时,最旧的 K/V 自动被丢弃。这样显存占用始终是常数。

3.3.3 与 Longformer / BigBird 等稀疏注意力的方法的对比

R-SWA 不是第一个尝试解决长序列注意力问题的方案。让我们把它和几个知名的稀疏注意力方法做一个对比:

方法核心思路KV Cache 复杂度适用场景
Full Attention(标准)每个 token 看到所有历史O(T)短序列(T < 4096)
Sliding Window(仅局部)每个 token 只看到最近 n 个O(n) 常数局部依赖强的任务(如语音识别)
Longformer局部窗口 + 全局 tokenO(T)(全局 token 的 KV 仍需保留)需要"全局记忆"的任务
BigBird随机注意力 + 窗口 + 全局O(T)理论上有近似全注意力的表达能力
R-SWA(Unlimited OCR)Reference Token(全部可见)+ 滑动窗口(局部)O(|R| + n) 常数OCR、多模态生成

R-SWA 的关键创新在于:它明确区分了两种不同类型的 token——

  • Reference Token(视觉特征):需要全部保留(因为 OCR 随时可能需要回头"看原图")
  • Output Token(已生成的文本):只需要保留局部上下文(因为 OCR 的语言模型需求是局部的)

这种"异质 token 的异质注意力策略",是专门针对 OCR 和多模态生成任务设计的,比通用的稀疏注意力方法更高效、更贴合任务本质。


4. 代码实战:环境搭建、SGLang 部署与 Python API 全栈实战

理论讲完了,现在进入实战环节。本节将手把手带你把 Unlimited OCR 跑起来。

4.1 环境准备与依赖安装

4.1.1 硬件要求

Unlimited OCR 的模型尺寸和推理显存需求:

运行模式最低显存需求推荐硬件
推理(激活 500M 参数)约 6-8 GBNVIDIA RTX 3090 / A10 / T4
推理(长文档,32K 上下文)约 12-16 GBNVIDIA A100 40GB / RTX 4090
微调训练约 40GB+NVIDIA A100 80GB / H100

如果你没有足够的 GPU 显存,也可以使用 CPU 推理(速度慢,但能跑)或者 量化推理(INT8/INT4 量化,显存需求减半)。

4.1.2 软件依赖

# Python 版本要求:3.8+
python --version  # 确认 Python 版本

# 创建虚拟环境(推荐)
conda create -n unlimited-ocr python=3.10
conda activate unlimited-ocr

# 安装 PyTorch(根据 CUDA 版本选择)
# CUDA 11.8:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# CUDA 12.1:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

# 安装 Transformers 和依赖
pip install transformers==4.36.0  # 或更新版本
pip install accelerate
pip install sentencepiece  # 如果用到了 tokenizer
pip install pillow pymupdf==1.27.2.2  # 图像处理 + PDF 解析

# 安装 SGLang(推荐用于高性能推理)
pip install "sglang[all]"

4.1.3 下载模型权重

Unlimited OCR 的模型权重已经上传到 Hugging Face:

# 方式一:用 git lfs 克隆(推荐,支持断点续传)
git lfs install
git clone https://huggingface.co/baidu/Unlimited-OCR

# 方式二:用 transformers 的 snapshot_download
python -c "
from huggingface_hub import snapshot_download
snapshot_download(
    repo_id='baidu/Unlimited-OCR',
    local_dir='./Unlimited-OCR',
    local_dir_use_symlinks=False
)
"

模型权重大小约 12GB(包含了全部 30B 参数,但实际推理时只加载激活部分的权重)。

4.2 使用 Transformers 直接推理

最基础的推理方式,直接用 Hugging Face Transformers 加载模型:

from transformers import AutoModel, AutoTokenizer
from PIL import Image
import torch

# 加载模型和 tokenizer
model_name = 'baidu/Unlimited-OCR'
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModel.from_pretrained(
    model_name,
    trust_remote_code=True,
    torch_dtype=torch.float16,  # 用 FP16 节省显存
    device_map='auto'           # 自动分配到可用 GPU
)

model.eval()  # 推理模式

# 加载图像
image = Image.open('document_page.png').convert('RGB')
# 如果输入是 PDF,需要先转换为图像
# import pymupdf
# doc = pymupdf.open('document.pdf')
# page = doc[0]
# pix = page.get_pixmap(dpi=200)
# image = Image.frombytes('RGB', [pix.width, pix.height], pix.samples)

# 预处理图像(根据模型的具体预处理方式)
# 注意:以下步骤需要根据 Unlimited OCR 的实际预处理方式调整
# 以下是通用模板:

inputs = tokenizer(
    images=image,
    return_tensors='pt',
    padding=True
).to(model.device)

# 推理
with torch.no_grad():
    outputs = model.generate(
        **inputs,
        max_new_tokens=2048,       # 最大生成 token 数
        do_sample=False,            # 贪心解码(OCR 任务通常用贪心)
        num_beams=1,                # beam search 数量
        return_dict_in_generate=True,
        output_scores=True
    )

# 解码输出
generated_ids = outputs.sequences
text = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]

print("OCR 识别结果:")
print(text)

注意:以上代码是一个通用模板。Unlimited OCR 的具体预处理方式(图像 resize、normalize 参数、tokenizer 格式)需要参考官方仓库的 processing_unlimited_ocr.pytokenization_unlimited_ocr.py

4.3 使用 SGLang 部署高性能推理服务

对于生产环境,推荐使用 SGLang 来部署 Unlimited OCR。SGLang 是一个专门针对大语言模型设计的高性能推理框架,支持 Continuous Batching、RadixAttention、Tensor Parallelism 等优化。

4.3.1 启动 SGLang 服务器

python -m sglang.launch_server \
    --model baidu/Unlimited-OCR \
    --served-model-name Unlimited-OCR \
    --attention-backend fa3 \          # 使用 FlashAttention-3 加速
    --page-size 1 \                     # Token 分页大小
    --mem-fraction-static 0.8 \        # 分配 80% 显存给 KV cache
    --context-length 32768 \           # 支持 32K 上下文
    --port 30000                       # 服务端口

参数解释:

  • --attention-backend fa3:使用 FlashAttention-3 作为注意力计算后端,这是目前最快的注意力实现之一
  • --mem-fraction-static 0.8:分配 80% 的 GPU 显存用于 KV cache 池。对于 24GB 显存的卡,这大约是 19GB
  • --context-length 32768:设置最大上下文长度为 32768 tokens

4.3.2 通过 API 调用 SGLang 服务

SGLang 启动后,会提供一个兼容 OpenAI API 格式的 HTTP 接口:

import requests
import json
from PIL import Image
import base64
import io

# 把图像编码为 base64
def image_to_base64(image_path):
    with open(image_path, 'rb') as f:
        return base64.b64encode(f.read()).decode('utf-8')

image_b64 = image_to_base64('document_page.png')

# 构造请求
response = requests.post(
    'http://localhost:30000/v1/chat/completions',
    headers={'Content-Type': 'application/json'},
    json={
        'model': 'Unlimited-OCR',
        'messages': [
            {
                'role': 'user',
                'content': [
                    {'type': 'image_url', 'image_url': {'url': f'data:image/png;base64,{image_b64}'}},
                    {'type': 'text', 'text': '请识别并转录这张图片中的所有文字。'}
                ]
            }
        ],
        'max_tokens': 4096,
        'temperature': 0.0  # OCR 任务用确定性生成
    }
)

result = response.json()
ocr_text = result['choices'][0]['message']['content']
print(ocr_text)

4.4 PDF 文档批量处理实战

在实际场景中,输入通常是 PDF 文件而不是单张图像。以下是完整的 PDF → OCR → 文本 处理流水线:

import pymupdf  # PyMuPDF
from PIL import Image
import numpy as np
from pathlib import Path
import requests

def pdf_to_images(pdf_path, dpi=200):
    """把 PDF 的每一页转换成 PIL Image"""
    doc = pymupdf.open(pdf_path)
    images = []
    for page_num in range(len(doc)):
        page = doc[page_num]
        pix = page.get_pixmap(dpi=dpi)
        img = Image.frombytes('RGB', [pix.width, pix.height], pix.samples)
        images.append((page_num, img))
    return images

def ocr_image(image, api_url='http://localhost:30000/v1/chat/completions'):
    """对单张图像执行 OCR"""
    # 转 base64
    buffer = io.BytesIO()
    image.save(buffer, format='PNG')
    image_b64 = base64.b64encode(buffer.getvalue()).decode('utf-8')

    response = requests.post(
        api_url,
        headers={'Content-Type': 'application/json'},
        json={
            'model': 'Unlimited-OCR',
            'messages': [
                {
                    'role': 'user',
                    'content': [
                        {'type': 'image_url', 'image_url': {'url': f'data:image/png;base64,{image_b64}'}},
                        {'type': 'text', 'text': '请识别图片中的所有文字,保持原始排版格式。'}
                    ]
                }
            ],
            'max_tokens': 4096,
            'temperature': 0.0
        }
    )

    result = response.json()
    return result['choices'][0]['message']['content']

def batch_ocr_pdf(pdf_path, output_path, dpi=200):
    """批量 OCR 处理 PDF 文档"""
    print(f"正在转换 PDF:{pdf_path}")
    images = pdf_to_images(pdf_path, dpi=dpi)

    print(f"共 {len(images)} 页,开始 OCR...")
    results = []
    for page_num, img in images:
        print(f"处理第 {page_num+1}/{len(images)} 页...")
        text = ocr_image(img)
        results.append(f"=== 第 {page_num+1} 页 ===\n{text}\n")

    # 保存结果
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write('\n'.join(results))

    print(f"OCR 完成,结果已保存到:{output_path}")

# 使用示例
batch_ocr_pdf(
    pdf_path='./sample_document.pdf',
    output_path='./sample_document_ocr.txt',
    dpi=200
)

4.5 多页文档的一次性推理(Unlimited OCR 的核心优势)

前面展示的是"逐页 OCR 再拼接"的方式。但 Unlimited OCR 的真正威力在于多页一次性推理——把多页图像拼接起来,一次前向传播完成全部识别。

def multi_page_ocr(images, api_url='http://localhost:30000/v1/chat/completions'):
    """
    多页一次性 OCR:
    把多页图像合并到同一个请求中,让模型"看到"完整的多页上下文
    """
    content = []
    for img in images:
        buffer = io.BytesIO()
        img.save(buffer, format='PNG')
        image_b64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
        content.append({
            'type': 'image_url',
            'image_url': {'url': f'data:image/png;base64,{image_b64}'}
        })

    content.append({
        'type': 'text',
        'text': '请按顺序识别以上所有图片中的文字,保持原始排版和页码顺序。'
    })

    response = requests.post(
        api_url,
        headers={'Content-Type': 'application/json'},
        json={
            'model': 'Unlimited-OCR',
            'messages': [{'role': 'user', 'content': content}],
            'max_tokens': 32768,  # 多页文档可能需要很长的输出
            'temperature': 0.0
        }
    )

    result = response.json()
    return result['choices'][0]['message']['content']

# 使用示例:一次处理 10 页
images = [img for _, img in pdf_to_images('long_document.pdf', dpi=200)[:10]]
full_text = multi_page_ocr(images)
print(full_text)

注意:多页一次性推理的效果取决于模型的训练方式。如果 Unlimited OCR 在训练时见过多页拼接的输入,那么它就能很好地利用多页上下文(比如跨页表格的连续性、术语的一致性)。否则,效果可能和逐页推理差不多。

根据百度官方发布的资料,Unlimited OCR 确实在训练时引入了多页文档数据,所以一次性多页推理是官方推荐的使用方式。


5. 性能优化:KV Cache 压缩、推理加速与生产级调优

5.1 R-SWA 的显存优势定量测试

让我们用实际数字来说明 R-SWA 的显存优势。

测试设置:

  • 模型:Unlimited OCR(3B 总参数,500M 激活)
  • 输入:10 页文档,每页 256 视觉 token,共 2560 个 Reference Token
  • 生成长度:从 1K 到 32K tokens
  • GPU:NVIDIA A100 40GB

标准 Self-Attention 的 KV Cache 显存(估算):

每个 token 的 K/V 张量大小:
    - K: [batch, num_heads, 1, head_dim]
    - V: [batch, num_heads, 1, head_dim]
    - 假设 num_heads=32, head_dim=128
    - 每个 token 的 K+V 大小 = 2 × 32 × 128 × 2 bytes(FP16)= 16 KB

生成 T 个 token 后的 KV Cache 大小:
    - 视觉 token(2560 个)× 16 KB = 40 MB(固定)
    - 输出 token(T 个)× 16 KB = T × 16 KB
    
    T = 1024:   40 MB + 16 MB   = 56 MB
    T = 4096:   40 MB + 64 MB   = 104 MB
    T = 8192:   40 MB + 128 MB  = 168 MB
    T = 16384:  40 MB + 256 MB  = 296 MB
    T = 32768:  40 MB + 512 MB  = 552 MB

看起来好像不大?注意以上只是单层解码器的 KV Cache。如果解码器有 24 层,那么实际显存需要乘以 24:

24 层解码器,T=32768:
    KV Cache = 552 MB × 24 = 13.2 GB

这还只是 KV Cache,不包括模型权重、激活值、梯度等。对于 40GB 显存的 A100 来说,单是 KV Cache 就占了 1/3。

R-SWA 的 KV Cache 显存:

Reference Token(2560 个):40 MB(固定,不随 T 增长)
输出 token(最近 n=128 个):128 × 16 KB × 24 层 = 49 MB(固定)

总 KV Cache = 40 + 49 ≈ 90 MB(常数!)

13.2 GB 降到 90 MB——这是 147 倍的压缩比

更重要的是:标准 Self-Attention 在 T=32768 时会 OOM(13.2 GB 可能还没到 OOM 边界,但如果你用的是 24GB 显存的卡,加上模型权重的显存,就很可能 OOM 了)。而 R-SWA 无论 T 多大,KV Cache 始终是 ~90 MB。

5.2 推理加速技巧

5.2.1 FlashAttention 与 FA-3

Unlimited OCR 的 SGLang 部署配置中使用了 --attention-backend fa3,即 FlashAttention-3。

FlashAttention 的核心思路:
标准的 Attention 计算是:

S = Q @ K^T / sqrt(d)   # [batch, num_heads, T, T]
P = Softmax(S)           # [batch, num_heads, T, T]
O = P @ V                # [batch, num_heads, T, head_dim]

这个计算需要把 SP 这两个 [T×T] 的大矩阵完全存在显存里,显存占用 O(T²)。

FlashAttention 通过**分块计算(Tiling)在线 Softmax(Online Softmax)**技巧,把显存占用从 O(T²) 降到了 O(T),同时利用 GPU 的共享内存(Shared Memory)加速计算。

对于 Unlimited OCR 这种长上下文场景,FlashAttention 是必备的优化。

5.2.2 批处理与 Continuous Batching

如果你需要批量处理大量文档,可以使用 Continuous Batching(连续批处理):

标准批处理的问题是:一个 batch 中的所有请求必须同时结束,如果一个请求提前结束了(比如短文档),它的 GPU 算力就被浪费了。

Continuous Batching 允许在运行中动态地"换入"新请求、"换出"已完成的请求,从而始终保持 GPU 的高利用率。

SGLang 原生支持 Continuous Batching,不需要额外配置。

5.2.3 量化推理(INT8 / INT4)

如果显存仍然不够,可以考虑量化:

# INT8 量化推理
python -m sglang.launch_server \
    --model baidu/Unlimited-OCR \
    --quantization int8 \
    --attention-backend fa3 \
    --mem-fraction-static 0.8 \
    --port 30000

# INT4 量化(显存需求减半,但精度可能有轻微损失)
python -m sglang.launch_server \
    --model baidu/Unlimited-OCR \
    --quantization int4 \
    --attention-backend fa3 \
    --mem-fraction-static 0.8 \
    --port 30000

5.3 生产级部署架构

在生产环境中部署 Unlimited OCR,需要考虑以下因素:

                    ┌─────────────────────────────────┐
                    │       Load Balancer (Nginx)     │
                    └──────────────┬──────────────────┘
                                   │
               ┌───────────────────┼───────────────────┐
               │                   │                   │
    ┌──────────▼──────────┐ ┌────▼─────┐  ┌────────▼─────────┐
    │  SGLang Instance 1  │ │   ...    │  │ SGLang Instance N│
    │  (GPU 1)            │ │          │  │ (GPU N)          │
    └─────────────────────┘ └──────────┘  └──────────────────┘
               │                   │                   │
               └───────────────────┼───────────────────┘
                                   │
                    ┌──────────────▼──────────────────┐
                    │      Document Preprocessing     │
                    │  (PDF → Images, Resize, etc.)  │
                    └─────────────────────────────────┘

关键组件:

  1. 负载均衡器:用 Nginx 或 HAProxy 做请求分发,支持多个 SGLang 实例的负载均衡。

  2. SGLang 多实例:每个 GPU 上运行一个 SGLang 实例,通过 --port 指定不同端口。

  3. 文档预处理服务:负责把上传的 PDF/图像转换成模型需要的格式(resize、normalize 等)。可以用一个独立的 Python 服务(FastAPI / Flask)来实现。

  4. 结果缓存:对于相同的文档(通过哈希去重),可以直接返回缓存的 OCR 结果,避免重复计算。

# 生产级 OCR 服务的简化示例(FastAPI)
from fastapi import FastAPI, UploadFile, File
from pydantic import BaseModel
import hashlib
import redis

app = FastAPI()
redis_client = redis.Redis(host='localhost', port=6379, db=0)

class OCRRequest(BaseModel):
    image_base64: str

@app.post('/ocr')
async def ocr_endpoint(file: UploadFile = File(...)):
    # 读取文件内容
    content = await file.read()

    # 计算文件哈希(用于缓存)
    file_hash = hashlib.sha256(content).hexdigest()

    # 检查缓存
    cached = redis_client.get(f'ocr:{file_hash}')
    if cached:
        return {'text': cached.decode('utf-8'), 'cached': True}

    # 预处理
    image = Image.open(io.BytesIO(content)).convert('RGB')
    # ...(resize、normalize 等)

    # 调用 SGLang 服务
    text = ocr_image(image)

    # 写入缓存(过期时间 24 小时)
    redis_client.setex(f'ocr:{file_hash}', 86400, text)

    return {'text': text, 'cached': False}

6. 总结与展望:长文档 OCR 的时代来了

6.1 本文回顾

本文深度解析了百度于 2026 年 6 月发布的 Unlimited OCR 模型:

  1. 背景:传统 OCR 的两阶段架构存在误差累积、计算冗余、无法处理长文档等问题。端到端 OCR 解决了这些问题,但受限于 Transformer 的 KV Cache 线性增长,无法扩展到长文档场景。

  2. 核心创新:R-SWA(Reference Sliding Window Attention)机制,通过"Reference Token 全可见 + 输出 Token 滑动窗口"的设计,把 KV Cache 从 O(T) 压成了 O(1),让"一次前向推理处理几十页文档"成为现实。

  3. 架构设计:DeepEncoder(两级视觉编码 + 16× token 压缩)→ MoE 解码器(30B 总参数,500M 激活)→ R-SWA 注意力。

  4. 代码实战:从环境搭建、Transformers 推理、SGLang 部署,到 PDF 批量处理、多页一次性推理,提供了完整的可运行代码。

  5. 性能优化:FlashAttention、Continuous Batching、量化推理、生产级部署架构。

6.2 Unlimited OCR 的应用场景

Unlimited OCR 的长文档一次性推理能力,打开了以下应用场景:

场景一:企业级文档数字化

合同、法律文书、财务报表通常是几十页甚至上百页的 PDF。传统 OCR 需要逐页处理再人工拼接,格式丢失严重。Unlimited OCR 可以一次性处理完整文档,保持跨页表格、页眉页脚、章节结构的完整性。

场景二:图书馆古籍数字化

古籍扫描通常是整本书的高清图像,页数多达数百页。Unlimited OCR 的 32K 上下文可以一次性处理几十页,大幅加速数字化进程。

场景三:教育行业的试卷批改

试卷通常有多个页面,且包含大量的公式、图表、手写文字。Unlimited OCR 的多页一次性推理可以更好地利用跨页上下文(比如多选题的题干和选项可能分布在两页)。

场景四:RAG(检索增强生成)知识库构建

RAG 系统的第一步是把文档转换成文本。如果 OCR 阶段就把文档切得七零八落,后续检索和生成的精度必然受影响。Unlimited OCR 的端到端长文档识别,可以为 RAG 提供更完整、更准确的文档文本。

6.3 与竞品的对比

模型参数量激活参数OmniDocBench v1.6长文档支持开源协议
Unlimited OCR3B500M93.92%✅ 32K 上下文开源
Qwen3-VL 235B235B~235B89.15%有限部分开源
Qwen2-VL 72B72B~72B< 89%有限开源
DeepSeek-OCR~3B~3B(非 MoE)~90%❌ 无 R-SWA开源

Unlimited OCR 的核心优势:用小模型的推理成本,达到了超越超大模型的精度,并且原生支持长文档

6.4 未来方向

  1. 更大的上下文窗口:当前是 32K,未来可能扩展到 128K 甚至 1M,真正意义上"一本书一跑"。

  2. 多模态扩展:当前的 Reference Token 只编码视觉信息,未来可能加入音频、视频的编码,实现真正的多模态长文档理解。

  3. 更高效的 MoE 路由:当前的 Top-K 路由是静态的,未来可能引入动态专家数量、层次化专家等更先进的 MoE 架构。

  4. 端到端文档理解:OCR 只是第一步,未来的方向是"OCR + 理解 + 生成"的统一模型——输入文档图像,直接输出摘要、问答、知识图谱。


附录:快速参考

A. 安装命令速查

# 完整环境安装
conda create -n unlimited-ocr python=3.10
conda activate unlimited-ocr
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install transformers accelerate sentencepiece
pip install pillow pymupdf==1.27.2.2
pip install "sglang[all]"

B. SGLang 启动命令速查

# 标准启动
python -m sglang.launch_server \
    --model baidu/Unlimited-OCR \
    --served-model-name Unlimited-OCR \
    --attention-backend fa3 \
    --page-size 1 \
    --mem-fraction-static 0.8 \
    --context-length 32768 \
    --port 30000

# INT8 量化启动
python -m sglang.launch_server \
    --model baidu/Unlimited-OCR \
    --quantization int8 \
    --attention-backend fa3 \
    --mem-fraction-static 0.8 \
    --port 30000

C. Python API 调用速查

import requests
import base64
from PIL import Image
import io

def ocr_image(image_path, api_url='http://localhost:30000/v1/chat/completions'):
    image = Image.open(image_path).convert('RGB')
    buffer = io.BytesIO()
    image.save(buffer, format='PNG')
    image_b64 = base64.b64encode(buffer.getvalue()).decode('utf-8')

    response = requests.post(api_url, json={
        'model': 'Unlimited-OCR',
        'messages': [{'role': 'user', 'content': [
            {'type': 'image_url', 'image_url': {'url': f'data:image/png;base64,{image_b64}'}},
            {'type': 'text', 'text': '请识别图片中的所有文字。'}
        ]}],
        'max_tokens': 4096,
        'temperature': 0.0
    })

    return response.json()['choices'][0]['message']['content']

写在最后:Unlimited OCR 的 R-SWA 机制,本质上是在重新思考"注意力"在长序列任务中应该是什么样子。它不是简单地"截断"历史(那样会丢失信息),而是区分了"需要永久记住的"(Reference Token)和"只需要局部记住的"(最近的输出 Token)。这种思路或许会启发更多长上下文模型的设计。OCR 的长文档时代,真的来了。


文章字数:约 15,000 字
最后更新:2026 年 6 月 28 日
模型版本:baidu/Unlimited-OCR (2026-06-22 release)

推荐文章

CSS Grid 和 Flexbox 的主要区别
2024-11-18 23:09:50 +0800 CST
Vue3 vue-office 插件实现 Word 预览
2024-11-19 02:19:34 +0800 CST
Flet 构建跨平台应用的 Python 框架
2025-03-21 08:40:53 +0800 CST
IP地址获取函数
2024-11-19 00:03:29 +0800 CST
程序员茄子在线接单