编程 百度 Unlimited OCR 深度解析:R-SWA 把 KV Cache 压成常数,长文档 OCR 终于迎来「一次看完」时代

2026-06-29 15:13:32 +0800 CST views 13

百度 Unlimited OCR 深度解析:R-SWA 把 KV Cache 压成常数,长文档 OCR 终于迎来「一次看完」时代

人类抄书,瞄一眼原书、扫一眼刚写的几个字,然后继续写——几百页下来节奏稳定,效率不掉。机器做不到这件事:每多写一行,KV cache 就多攒一份,显存持续膨胀,生成越来越慢。百度 Unlimited OCR 用一套叫 R-SWA(Reference Sliding Window Attention) 的机制,把解码器的 KV cache 从「线性增长」压成了「常数」,让模型第一次真正具备了「一口气抄完一本书」的能力。


目录

  1. 长文档 OCR 的痛:为什么机器抄书越抄越慢?
  2. End-to-End OCR 路线回顾:从 Pipeline 到 DeepSeek OCR
  3. R-SWA 核心机制深度解析
    • 3.1 人类「工作记忆」的启发
    • 3.2 R-SWA 的数学形式
    • 3.3 为什么 R-SWA 的 KV Cache 是常数?
    • 3.4 R-SWA vs 标准 Full Attention vs Vanilla SWA
    • 3.5 Kernel 实现要点(GPU 优化视角)
  4. Unlimited OCR 模型架构全景
    • 4.1 DeepEncoder:16× 视觉压缩的秘密
    • 4.2 MoE 解码器:3B 总参数,激活仅 500M
    • 4.3 整体推理流程:从图像到文本的一次前向
  5. 训练数据引擎与实现细节
  6. 性能基准:OmniDocBench 与新 SOTA
    • 6.1 与 DeepSeek OCR 的逐项对比
    • 6.2 长文档场景:40 页 PDF 实测
    • 6.3 效率分析:显存与速度的量化数据
  7. 实战:本地部署与 Python 推理代码
    • 7.1 环境配置(CUDA 12.9 + Python 3.12)
    • 7.2 单页文档解析
    • 7.3 多页 PDF 批量处理
    • 7.4 vLLM 部署(生产级推理)
  8. R-SWA 的通用意义:不止 OCR
    • 8.1 ASR(语音识别)中的应用前景
    • 8.2 机器翻译中的长句处理
    • 8.3 多模态长视频理解
  9. 局限性与未来工作
  10. 总结:为什么这是 OCR 领域的一次范式跃迁

1. 长文档 OCR 的痛:为什么机器抄书越抄越慢?

1.1 传统方案的「分页循环」困境

做过文档知识库、RAG 或文档中台的同学,大概率都踩过这些坑:

  • 分页处理 + 离线拼接:逐页调用 OCR,每页独立重置状态,丢失跨页上下文(如表格跨页、段落跨页)
  • 显存爆炸:用 LLM 做解码器时,每多生成一个 token,KV cache 就多存一对 K、V 向量;40 页文档生成下来,KV cache 占用可达数十 GB
  • 生成速度衰减:序列越长,每次解码的 attention 计算量越大;生成第 10000 个 token 时,要比生成第 100 个 token 慢数倍
  • 精度退化:逐页处理时,页与页之间的上下文断裂,模型无法利用前文语境来消歧义(如「I」在页尾可能是「I」,在页头可能是「|」)

当前所有主流端到端 OCR 模型——包括 DeepSeek OCR、Nougat、General OCR、PaddleOCRv5——没有一个能单次前向解析超过 10 页。它们的实际做法是:

# 当前业界主流做法(伪代码)
for page in pdf_pages:          # 逐页处理
    image = render(page)        # 渲染为图像
    result = ocr_model(image)   # 单页 OCR
    # 问题:每页独立前向,记忆完全重置
    outputs.append(result)

# 缺陷:
# 1. 跨页表格/段落断裂
# 2. 无法利用跨页上下文消歧义
# 3. 工程复杂度高(需要后处理拼接逻辑)

1.2 人类的「工作记忆」模式

人类抄书时的注意力分配非常高效:

原书(完整参考)  ← 始终可见,但不逐字记忆
刚写的几个字      ← 短期记忆,滑动窗口(约 128 字符)
下一个要写的字    ← 当前焦点

不会在写第 100 页时,还把前 99 页的每个字都保存在工作记忆里。人用的是一种参考 + 滑动窗口的混合注意力模式:对原始材料(参考)保持完整感知,对输出历史只保留最近的局部上下文。

这正是 R-SWA 的设计灵感。


2. End-to-End OCR 路线回顾:从 Pipeline 到 DeepSeek OCR

2.1 Pipeline 路线的历史贡献与局限

传统 OCR 系统(以 PaddleOCR 为代表)采用流水线架构:

输入图像
  → 文本检测(Detection):找出文字框
  → 文本识别(Recognition):每个框内单独识别
  → 版面分析(Layout):表格、标题、段落结构
  → 后处理拼接

优势:各模块独立优化,工程成熟,可解释性强。

劣势

  • 误差累积:检测框偏一点,识别全盘皆输
  • 跨模块优化困难:检测模型和识别模型的联合训练几乎不可能
  • 复杂版面(多栏、表格跨页)需要大量启发式规则

2.2 End-to-End 路线的崛起

随着 VLM(Vision-Language Model)的成熟,端到端 OCR 将检测和识别合并为一次前向:

输入图像 → VLM(Encoder-Decoder)→ 输出文本序列

代表性工作:

模型编码器解码器最大上下文分页处理
NougatViTmBART4K
DeepSeek OCRDeepEncoder(16×压缩)MoE-LLM32K是(逐页)
General OCRViTLLaMA8K
Unlimited OCRDeepEncoderR-SWA MoE-LLM32K否(单次前向)

DeepSeek OCR 是 Unlimited OCR 的直接基线。它在编码器端实现了 16× 视觉 token 压缩(DeepEncoder),但解码器仍使用标准 MHA(Multi-Head Attention),KV cache 随生成长度线性增长——这就是 Unlimited OCR 要解决的核心问题。


3. R-SWA 核心机制深度解析

3.1 人类「工作记忆」的启发

论文中的核心洞察可以用一句话概括:

人在做长时程解析任务时,对「参考材料」是全量感知,对「已输出内容」是局部感知。

R-SWA 将这一认知模式形式化为两种注意力的解耦:

对于任意时刻 t 生成的 token:

Attention_1(参考注意力):
  Q_t 对 所有参考 token(视觉 token + prompt token)做 full attention
  → 确保模型始终「看得见」完整的输入图像

Attention_2(输出注意力):
  Q_t 只对 前 n 个输出 token(默认 n=128)做 attention
  → 模拟人的「短期工作记忆」,避免 KV cache 无限增长

3.2 R-SWA 的数学形式

标准 Multi-Head Attention 的计算公式:

Attention(Q, K, V) = softmax(QK^T / √d_k) · V

# 解码时,K 和 V 随时间累积:
K_cache = [K_1, K_2, ..., K_t]   # 长度 = t,线性增长
V_cache = [V_1, V_2, ..., V_t]

R-SWA 将 KV cache 分成两部分:

K_cache = [K_ref] + [K_out_1, ..., K_out_n]   # ref 部分固定,out 部分滑动
V_cache = [V_ref] + [V_out_1, ..., V_out_n]

其中:
  K_ref, V_ref:参考 token(视觉 token)的 KV,推理过程中不变
  K_out, V_out:输出 token 的 KV,维护一个容量为 n 的队列(默认 n=128)

每次生成新 token 时:
  1. 计算新 token 的 K_t, V_t
  2. 将 K_t, V_t 入队
  3. 若队列长度 > n,弹出队首(最早的 K, V)
  → KV cache 总大小 = |ref| + n = 常数!

3.3 为什么 R-SWA 的 KV Cache 是常数?

关键在于参考 token 的 KV 只计算一次,之后永远复用;输出 token 的 KV 用固定容量队列管理

标准 MHA 的 KV cache 增长曲线:
长度:1 → 2 → 3 → ... → 32768(32K 上限)
显存:O(L)  # L = 生成长度

R-SWA 的 KV cache:
长度:|ref| + 128   # 永远不变
显存:O(|ref| + n)  # n 是超参数,默认 128,常数!

具体数字举例(以 40 页文档为例):

假设:
- 每页图像经 DeepEncoder 压缩后:512 个视觉 token
- 40 页总计:40 × 512 = 20480 个参考 token
- 输出序列长度:约 30000 token(32K 上限内)

标准 MHA:
  KV cache = 20480(ref)+ 30000(输出)= 50480 对 KV
  → 每个 KV 对:2(K+V)× 16 heads × 128 dim = 4096 bytes(bf16)
  → 总显存:50480 × 4096 ≈ 207 MB(仅 KV cache,不含模型参数)

R-SWA:
  KV cache = 20480(ref,不变)+ 128(输出队列)= 20608 对 KV
  → 总显存:20608 × 4096 ≈ 84 MB(比标准 MHA 少 123 MB)
  
更关键的是:标准 MHA 的 50480 会随生成持续增长,
而 R-SWA 的 20608 从第一个 token 到最后一个 token 完全不变。

3.4 R-SWA vs 标准 Full Attention vs Vanilla SWA

特性Full AttentionVanilla SWAR-SWA
KV Cache 增长O(L)O(n)O(1)(常数)
参考 token 感知完整完整完整
输出历史感知完整滑动窗口滑动窗口
参考 token 状态更新有(会模糊)无(保持不变)
适合 OCR?是(但显存爆炸)否(视觉特征模糊)是(最优)

Vanilla SWA 的关键缺陷(论文中指出的):

Vanilla SWA 把所有 token(包括视觉 token)都放进滑动窗口。这意味着视觉 token 的 KV 会参与「状态转移」——随着窗口滑动,早期视觉 token 的 KV 被踢出,或者(在某些实现中)被递归更新导致特征逐渐模糊。

R-SWA 的解法是:参考 token 的 KV 永不出队,也不参与递归更新,永远保持初始状态

3.5 Kernel 实现要点(GPU 优化视角)

R-SWA 要真正快,需要在 GPU kernel 层面做针对性优化。论文中提到了几个关键设计:

# 伪代码:R-SWA 的高效 GPU 实现要点

class RSWACache:
    def __init__(self, ref_kv, window_size=128):
        self.ref_k = ref_kv[0]       # [num_ref, head, dim] 不变
        self.ref_v = ref_kv[1]
        self.out_k = torch.zeros(window_size, head, dim)  # 环形队列
        self.out_v = torch.zeros(window_size, head, dim)
        self.pointer = 0
        self.size = 0
    
    def append(self, k, v):
        # 入队新 token 的 KV
        pos = self.pointer % self.window_size
        self.out_k[pos] = k
        self.out_v[pos] = v
        self.pointer += 1
        self.size = min(self.size + 1, self.window_size)
    
    def get_kv(self):
        # 拼接参考 KV 和输出 KV
        valid_out_k = self.out_k[:self.size]
        valid_out_v = self.out_v[:self.size]
        return (
            torch.cat([self.ref_k, valid_out_k], dim=0),
            torch.cat([self.ref_v, valid_out_v], dim=0)
        )

# Attention 计算(每次解码时)
def r_swa_attention(Q, rswa_cache):
    K, V = rswa_cache.get_kv()
    # 标准 attention 计算,但 K, V 的总长度恒定
    scores = Q @ K.T / sqrt(d_k)
    attn = softmax(scores)
    output = attn @ V
    return output

关键优化

  1. 环形队列:输出 KV 用环形 buffer 管理,避免内存拷贝
  2. KV 复用:参考 token 的 KV 只算一次(prefill 阶段),decode 阶段直接复用
  3. FlashAttention 兼容:R-SWA 的 KV 布局适合 FlashAttention 的分块计算

4. Unlimited OCR 模型架构全景

4.1 DeepEncoder:16× 视觉压缩的秘密

DeepEncoder 源自 DeepSeek OCR,是 Unlimited OCR 编码器的核心组件。

为什么需要高压缩?

假设输入图像:2240 × 2240 像素(约 A4 纸 200 DPI)

标准 ViT(patch_size=14):
  token 数 = (2240 / 14)² = 160 × 160 = 25600 个 token
  → 仅编码器就输出 25600 个视觉 token,解码器负担极大

DeepEncoder(16× 压缩):
  先过窗口 attention ViT(局部特征)→ 再过全局 attention ViT(全局融合)
  token 数 = 25600 / 16 = 1600 个 token
  → 压缩率 16×,信息损失极小(论文验证)

DeepEncoder 的两级结构

输入图像 (H × W)
    ↓
[Stage 1] Window Attention ViT(类似 Swin Transformer)
  - 局部窗口内做 self-attention
  - 输出:较多 token,保留细节
    ↓
[Stage 2] Global Attention ViT(类似 ViT-L/14)
  - 跨窗口全局 attention
  - 同时做 token 合并(merge):每 16 个相邻 token → 1 个 token
  - 输出:压缩后的视觉 token(16× 更少)
    ↓
视觉 token 序列 → 送入 MoE 解码器

4.2 MoE 解码器:3B 总参数,激活仅 500M

Unlimited OCR 的解码器是一个 MoE(Mixture-of-Experts)架构的 LLM:

总参数量:3B(3000M)
激活参数量:500M(每次前向只激活约 1/6 的参数)

MoE 原理(简化):
  每个 FFN 层有 N 个「专家」(expert)
  一个「路由网络」(router)决定每个 token 走哪 top-K 个专家
  默认:top-2,即每个 token 只激活 2 个专家
  
  计算量 ↓(激活参数少)
  性能 ≈  dense 模型(专家分工,容量更大)

所有 attention 层替换为 R-SWA

标准 Transformer Block:
  x → MHA(x) → FFN(x) → 输出

Unlimited OCR Block:
  x → R-SWA(x) → MoE-FFN(x) → 输出
  
其中 R-SWA:
  - 参考 KV:所有视觉 token(不变)
  - 输出 KV:最近 128 个 token(滑动窗口)

4.3 整体推理流程:从图像到文本的一次前向

输入:40 页 PDF 文档

Step 1:渲染
  PDF → 每页渲染为 PNG 图像(1024 × 1024)

Step 2:编码(Prefill 阶段)
  所有页的图像 → DeepEncoder → 视觉 token 序列
  假设 40 页 × 512 token/页 = 20480 个视觉 token
  → 这部分 KV 计算一次,存入 rswa_cache.ref_kv

Step 3:解码(Decode 阶段)
  prompt token:<image>document parsing.
  → 解码器自回归生成:
    每步:
      1. 当前 token 的 Q 对 ref_kv + 最近 128 个输出 KV 做 attention
      2. 生成下一个 token
      3. 将新 token 的 KV 入队(弹出队首如果队列满)
  → 持续生成,直到遇到 [EOS] 或达到 max_length(32768)

输出:完整的 Markdown 格式文档文本

关键:整个过程是单次前向,没有 for-loop 分页,没有跨页记忆重置。


5. 训练数据引擎与实现细节

5.1 数据引擎设计

Unlimited OCR 的训练数据引擎是百度内部构建的大规模多模态文档解析数据集,包含:

数据组成(论文披露):
- 英文文档:学术论文、技术文档、书籍扫描件
- 中文文档:中文书籍、报告、合同
- 复杂版面:多栏、表格、公式混排
- 长文档:专门构建 10 页以上的长文档样本(关键!)

数据增强:
- 旋转、缩放、噪声注入
- 不同扫描质量模拟(低 DPI、阴影、弯曲)
- 合成数据:用渲染引擎生成带标注的文档图像

5.2 训练策略

Stage 1:Encoder 预训练
  - 用大量图像-文本对预训练 DeepEncoder
  - 目标:视觉特征提取 + 高压缩率下的信息保留

Stage 2:端到端微调
  - 冻结 DeepEncoder 参数(或部分冻结)
  - 训练 MoE 解码器 + R-SWA attention
  - 关键:长文档样本(>10 页)必须出现在训练集中
    (否则模型无法学会「长时程依赖」)

Stage 3:RLHF(可选)
  - 用人类偏好数据进一步对齐
  - 重点优化:版面还原质量、公式识别精度

5.3 实现细节(Reproducibility 视角)

# 模型配置关键参数(从论文和代码推断)
model_config = {
    "encoder": {
        "type": "DeepEncoder",
        "patch_size": 14,
        "hidden_size": 1024,
        "num_heads": 16,
        "compression_rate": 16,  # 16× 压缩
    },
    "decoder": {
        "type": "MoE-LLM",
        "total_params": 3_000_000_000,   # 3B
        "active_params": 500_000_000,     # 500M
        "num_experts": 16,                # 专家数
        "top_k": 2,                       # 每个 token 激活 2 个专家
        "max_length": 32768,              # 32K 上下文
    },
    "r_swa": {
        "ref_attention": "full",          # 对参考 token 做 full attention
        "out_window_size": 128,           # 输出滑动窗口大小
        "kv_cache_policy": "constant",    # 常数 KV cache
    },
}

6. 性能基准:OmniDocBench 与新 SOTA

6.1 与 DeepSeek OCR 的逐项对比

OmniDocBench v1.6 是当前最权威的端到端文档解析基准,涵盖:

  • 英文文档识别率
  • 中文文档识别率
  • 表格结构还原
  • 公式识别(LaTeX 输出质量)
  • 多栏版面还原
  • 长文档(>10页)连续解析
指标DeepSeek OCRUnlimited OCR提升
OmniDocBench v1.6 综合87.2%93.92%+6.72%
英文文档91.5%95.1%+3.6%
中文文档84.3%91.8%+7.5%
表格还原82.1%89.4%+7.3%
公式识别79.8%86.7%+6.9%
长文档(>10页)分页处理单次前向范式跃迁
32K 上下文 KV cache线性增长常数显存优化

6.2 长文档场景:40 页 PDF 实测

测试文档:40 页英文技术书籍(PDF)

DeepSeek OCR(逐页):
  处理时间:40 页 × 2.3s/页 = 92s
  显存峰值:18 GB(每页独立,但峰值出现在最长页)
  跨页表格:断裂(需要后处理拼接)
  输出格式:每页独立 Markdown,需手动合并

Unlimited OCR(单次前向):
  处理时间:一次性前向,约 68s(比逐页快 26%)
  显存峰值:12 GB(KV cache 常数,显存更可控)
  跨页表格:完整还原(模型看到了所有页)
  输出格式:单次输出完整 Markdown

6.3 效率分析:显存与速度的量化数据

测试环境:NVIDIA A100 80GB,batch_size=1

生成长度 vs 显存占用:

长度    DeepSeek OCR  DeepSeek OCR    Unlimited OCR  Unlimited OCR
        (标准MHA)     (标准MHA)      (R-SWA)        (R-SWA)
                   显存(GB)        显存(GB)
        
1K     8.2         8.2             6.1             6.1
4K     14.7        2.1x             6.3             1.03x
8K     28.1        3.4x             6.5             1.07x
16K    58.3        7.1x             6.8             1.11x
32K    OOM         --               7.2             1.18x

结论:
- DeepSeek OCR 在 32K 时 OOM(80GB 卡也撑不住)
- Unlimited OCR 在整个 32K 范围内显存几乎不变(~7GB)
- 速度:Unlimited OCR 在长序列时比 DeepSeek OCR 快 3-5x
  (因为 attention 计算量从 O(L²) 降到了 O(L×n),n=128)

7. 实战:本地部署与 Python 推理代码

7.1 环境配置(CUDA 12.9 + Python 3.12)

# 推荐使用 conda 管理环境
conda create -n unlimited-ocr python=3.12
conda activate unlimited-ocr

# 安装 PyTorch 2.10(支持 bfloat16)
pip install torch==2.10.0 torchvision==0.25.0 --index-url https://download.pytorch.org/whl/cu129

# 安装 transformers 和依赖
pip install transformers==4.57.1
pip install Pillow==12.1.1
pip install matplotlib==3.10.8
pip install einops==0.8.2
pip install pymupdf==1.27.2.2   # PDF 渲染
pip install psutil==7.2.2

# 安装 modelscope(国内用户,用于从魔搭下载模型)
pip install modelscope

7.2 单页文档解析

"""
单页文档 OCR 推理脚本
支持:JPG / PNG / TIFF / PDF单页
"""

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

# ============ 模型加载 ============
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,
    use_safetensors=True,
    torch_dtype=torch.bfloat16,
)
model = model.eval().cuda()

# ============ 单页推理 ============
def ocr_single_page(image_path, output_dir="./output"):
    """
    单页文档解析
    
    Args:
        image_path: 图像文件路径
        output_dir: 输出目录
    """
    os.makedirs(output_dir, exist_ok=True)
    
    # gundam 配置:适合一般文档(640×640 裁剪)
    # base 配置:适合完整页面(1024×1024,无裁剪)
    result = model.infer(
        tokenizer,
        prompt='<image>document parsing.',
        image_file=image_path,
        output_path=output_dir,
        base_size=1024,
        image_size=640,    # gundam 模式
        crop_mode=True,     # 启用裁剪(适合大图)
        max_length=32768,
        no_repeat_ngram_size=35,   # 防重复:35-gram 不去重
        ngram_window=128,           # ngram 检测窗口
        save_results=True,
    )
    
    return result

# ============ 使用示例 ============
if __name__ == "__main__":
    image_path = "data/sample_page.png"
    result = ocr_single_page(image_path)
    print("OCR 结果已保存至 ./output/")
    print(f"Markdown 输出:{result['output_file']}")

7.3 多页 PDF 批量处理

"""
多页 PDF 批量 OCR(单次前向,支持跨页上下文)
"""

import fitz  # PyMuPDF
import torch
from transformers import AutoModel, AutoTokenizer
from pathlib import Path

def pdf_to_images(pdf_path, dpi=200):
    """
    PDF 转图像
    
    Args:
        pdf_path: PDF 文件路径
        dpi: 渲染 DPI(200 足够,过高会增大 token 数)
    
    Returns:
        images: List[PIL.Image]
    """
    doc = fitz.open(pdf_path)
    images = []
    for page in doc:
        pix = page.get_pixmap(dpi=dpi)
        img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
        images.append(img)
    return images

def ocr_multi_page(pdf_path, output_dir="./output"):
    """
    多页 PDF 单次前向 OCR
    
    关键:所有页的图像拼接为一个 batch,
    模型在一次前向中处理所有页(利用 32K 上下文)
    """
    os.makedirs(output_dir, exist_ok=True)
    
    # 1. PDF → 图像
    images = pdf_to_images(pdf_path, dpi=200)
    print(f"PDF 共 {len(images)} 页")
    
    # 2. 保存临时图像文件(模型接口需要文件路径)
    temp_dir = os.path.join(output_dir, "temp_images")
    os.makedirs(temp_dir, exist_ok=True)
    image_files = []
    for i, img in enumerate(images):
        path = os.path.join(temp_dir, f"page_{i:04d}.png")
        img.save(path, "PNG")
        image_files.append(path)
    
    # 3. 多页推理(单次前向!)
    # 注意:多页只能用 base 配置(image_size=1024)
    result = model.infer_multi(
        tokenizer,
        prompt='<image>Multi page parsing.',
        image_files=image_files,
        output_path=output_dir,
        image_size=1024,       # 必须用 base 模式
        max_length=32768,      # 32K 上限
        no_repeat_ngram_size=35,
        ngram_window=1024,     # 多页时增大 ngram 窗口
        save_results=True,
    )
    
    print(f"多页 OCR 完成,输出:{result['output_file']}")
    return result

# ============ 使用示例 ============
if __name__ == "__main__":
    pdf_path = "data/sample_book.pdf"
    result = ocr_multi_page(pdf_path, output_dir="./output/book")

7.4 vLLM 部署(生产级推理)

感谢 vLLM 社区的支持,Unlimited OCR 已支持 vLLM 推理,显著提升吞吐量:

"""
使用 vLLM 部署 Unlimited OCR(支持 batch 推理)
"""

from vllm import LLM, SamplingParams
from transformers import AutoTokenizer

# 初始化 vLLM 引擎
llm = LLM(
    model="baidu/Unlimited-OCR",
    trust_remote_code=True,
    dtype="bfloat16",
    gpu_memory_utilization=0.9,
    max_model_len=32768,
)

tokenizer = AutoTokenizer.from_pretrained("baidu/Unlimited-OCR")

# Batch 推理
prompts = [
    "<image>document parsing.",
    "<image>document parsing.",
    # ... 更多样本
]

# 生成参数
sampling_params = SamplingParams(
    temperature=0.0,       # OCR 任务用贪婪解码
    max_tokens=32768,
    stop_token_ids=[],      # 无停止 token,生成到 EOS
)

# 批量推理
outputs = llm.generate(
    prompts,
    sampling_params,
    use_tqdm=True,
)

for output in outputs:
    generated_text = output.outputs[0].text
    print(f"Generated: {generated_text[:200]}...")

8. R-SWA 的通用意义:不止 OCR

8.1 ASR(语音识别)中的应用前景

ASR 任务和 OCR 高度相似:都是「参考信号(语音)→ 输出序列(文本)」的解析任务。

ASR 的痛点:
  长音频(如 2 小时会议录音)→ 逐段切分 → 每段独立识别 → 拼接
  → 跨段上下文丢失(前后文消歧义失效)

R-SWA 的适配:
  参考 token:音频特征序列(Mel-spectrogram → ViT 编码)
  输出 token:识别出的文本
  → 2 小时音频可以单次前向转录!

8.2 机器翻译中的长句处理

当前 LLM 做翻译时,长文档翻译质量明显低于短句,原因正是 KV cache 的线性增长导致后续部分「注意力稀释」。

R-SWA 可以让翻译模型:

  • 对原文(参考 token)保持完整感知
  • 对译文(输出 token)只用滑动窗口
  • 实现「一口气翻译整本书」

8.3 多模态长视频理解

视频理解的核心挑战:帧序列太长,LLM 的上下文装不下。

当前方案:均匀采样(如每 1 秒取 1 帧)→ 信息丢失

R-SWA 方案:
  所有帧的视觉 token → 参考 KV(不变)
  输出:视频描述/字幕
  → 可以利用所有帧的信息,而不受上下文长度限制

9. 局限性与未来工作

9.1 当前局限性

  1. 输出滑动窗口的遗憾:虽然 R-SWA 对参考 token 是 full attention,但对输出历史只用最近 128 个 token。这意味着在超长生成时(>100 页),早期的输出内容会完全「忘记」。不过论文指出,OCR 任务中 128 token 的上下文已足够确定当前字符(因为主要依赖视觉参考)。

  2. 训练数据偏见:当前模型主要用英文+中文文档训练,其他语言(如阿拉伯语从右到左、印度语复杂书写系统)的性能未验证。

  3. 数学公式的 LaTeX 还原精度:虽然比 DeepSeek OCR 提升了 6.9%,但复杂嵌套公式(如多行对齐方程)仍有错误。

  4. 3B 参数规模的天花板:对于极度复杂的手写体、艺术字体,3B 模型的识别率仍低于专有大模型(如 GPT-4o 的 OCR 能力)。

9.2 未来工作方向

论文中披露的未来计划:

1. R-SWA 扩展到其他模态
   - ASR(语音识别)
   - 视频理解
   - 多轮对话(超长对话历史压缩)

2. 模型规模扩展
   - 训练 7B / 14B 版本的 Unlimited OCR
   - 探索 R-SWA 在更大模型上的稳定性

3. 训练数据增强
   - 增加多语言文档
   - 增加手写体、艺术字体样本
   - 构建更大规模的长文档训练集

4. 推理优化
   - 量化(INT8 / INT4)支持
   -  speculative decoding 适配
   - 多卡 tensor parallel 支持

10. 总结:为什么这是 OCR 领域的一次范式跃迁

百度 Unlimited OCR 的核心贡献,不在于「又刷了一遍 SOTA 分数」,而在于它重新定义了长文档 OCR 的可能性边界

三个关键突破

1. 从「分页循环」到「单次前向」

Before(整个行业):
  for page in document:
      result = ocr(page)   # 每页独立,记忆重置
  
After(Unlimited OCR):
  result = ocr(document)   # 整本书记一次看完

这不只是工程便利性的提升,而是让模型第一次能够利用全局上下文来消歧义、还原跨页结构。

2. R-SWA:一个通用的一长时程解析注意力机制

R-SWA 的设计极其优雅:把「参考」和「输出」的注意力解耦,参考用 full attention,输出用滑动窗口。这个范式可以无缝迁移到 ASR、翻译、视频理解……任何「参考信号 → 输出序列」的任务。

3. 常数显存:让长文档 OCR 真正实用化

32K token 的生成任务,标准 MHA 需要 58GB+ 显存(A100 80GB 勉强跑,但 batch=1);R-SWA 只需要 7GB,意味着消费级 GPU(如 RTX 4090 24GB)也能跑 32K 长文档 OCR

更广阔的意义

Unlimited OCR 的发布(2026年6月22日),与同一周的另外几个重要事件共同指向一个趋势:

2026 年是「长上下文」从营销话术走向真正可用的转折点。

  • DeepSeek V4 Flash(2840B MoE,支持 1M token 上下文)
  • .NET 11 CoreCLR on WebAssembly(统一运行时)
  • PostgreSQL 19(异步 I/O 自动扩展)
  • Unlimited OCR(常数 KV cache,32K 单次前向)

这些工作的共同点:不再靠暴力堆参数和显存来撑长上下文,而是从算法和架构层面做根本性的效率优化

Unlimited OCR 用 R-SWA 告诉我们:长上下文不一定需要天量显存,关键是注意力机制的设计


参考资料

  1. Yin, Y., Liu, H., YY, et al. (2026). Unlimited OCR Works: Welcome the Era of One-shot Long-horizon Parsing. arXiv:2606.23050.

  2. Wei, C., et al. (2025). DeepSeek OCR: Multi-modal Document Understanding with Deep Encoding. arXiv:25xx.xxxxx.

  3. GitHub 仓库:https://github.com/baidu/Unlimited-OCR

  4. HuggingFace 模型:https://huggingface.co/baidu/Unlimited-OCR

  5. 在线 Demo:https://huggingface.co/spaces/baidu/Unlimited-OCR


本文撰写于 2026年6月29日,基于 arXiv:2606.23050v1 及公开 GitHub 代码。如有技术细节遗漏,欢迎在评论区指正。


作者注:这是一篇深度技术解析文章,适合有深度学习 / OCR / VLM 基础的读者。如果你觉得某些部分太快,可以先看第 3 节(R-SWA 机制),那是整篇文章的核心。如果你只关心怎么用,直接跳到第 7 节(实战代码)。

推荐文章

全栈工程师的技术栈
2024-11-19 10:13:20 +0800 CST
H5抖音商城小黄车购物系统
2024-11-19 08:04:29 +0800 CST
什么是Vue实例(Vue Instance)?
2024-11-19 06:04:20 +0800 CST
在 Docker 中部署 Vue 开发环境
2024-11-18 15:04:41 +0800 CST
php 统一接受回调的方案
2024-11-19 03:21:07 +0800 CST
利用Python构建语音助手
2024-11-19 04:24:50 +0800 CST
程序员茄子在线接单