{"notes":[{"id":"text-spotting/nougat","category":"text-spotting","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"Nougat","subtitle":"鬼打墙","author":"Z. Yuan","paperDate":"2023-08-25","publishedOn":"2026-04-14","world":"external/nougat","paperTitle":"Nougat: Neural Optical Understanding for Academic Documents","paperUrl":"https://arxiv.org/abs/2308.13418","bibliography":{"title":"Nougat: Neural Optical Understanding for Academic Documents","authors":["Lukas Blecher","Guillem Cucurull","Thomas Scialom","Robert Stojnic"],"url":"https://arxiv.org/abs/2308.13418","pdfUrl":"https://arxiv.org/pdf/2308.13418v1","codeUrl":"https://github.com/facebookresearch/nougat","preprint":{"id":"2308.13418","submittedOn":"2023-08-25","url":"https://arxiv.org/abs/2308.13418"},"publication":null,"citation":"@misc{textspottingnougat2023,\n  title = {{Nougat: Neural Optical Understanding for Academic Documents}},\n  author = {Lukas Blecher and Guillem Cucurull and Thomas Scialom and Robert Stojnic},\n  year = {2023},\n  eprint = {2308.13418},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/2308.13418}\n}\n","citationPath":"/content/papers/citations/text-spotting/nougat.1d66a2aca861.bib"},"thumbnail":{"src":"/content/papers/assets/73888d5b579ab68d56551dc59d69ebcd0bf97704d288425f0341c9a9aa012138.png","width":1283,"height":288},"locale":"zh-hans","path":"/content/papers/zh-hans/text-spotting/nougat.7798de0230c7.md","headings":[{"id":"定义问题","text":"定义问题","depth":2},{"id":"解决问题","text":"解决问题","depth":2},{"id":"架构沿用-donut","text":"架构：沿用 Donut","depth":3},{"id":"数据把-latex-源码切成一页一页","text":"数据：把 LaTeX 源码切成一页一页","depth":3},{"id":"让数字-pdf-看起来像扫描件","text":"让数字 PDF 看起来像扫描件","depth":3},{"id":"讨论","text":"讨论","depth":2},{"id":"arxiv-测试集上的成绩","text":"arXiv 测试集上的成绩","depth":3},{"id":"陷入重复","text":"陷入重复","depth":3},{"id":"检测重复","text":"检测重复","depth":3},{"id":"社区的实际经验","text":"社区的实际经验","depth":3},{"id":"读这篇时要知道的事","text":"读这篇时要知道的事","depth":3},{"id":"结论","text":"结论","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[]}],"text":"把一篇论文的 PDF 丢进普通的 OCR 引擎，文字大多读得出来，数学公式却常常散成一堆符号。\n\n原因不难想象。$x_i^2$ 里，下标 $i$ 和上标 $2$ 叠在 $x$ 的右边；分数的分子和分母上下排列。逐行扫描的 OCR 把它们当成普通文字处理，位置关系就丢了。PDF 本身也帮不上多少忙：它记录的是「哪个字画在页面的哪个位置」，公式原本的 LaTeX 结构在编译时就已经丢掉了。\n\nMeta AI 在 2023 年 8 月提出的 Nougat，想一次解决这件事：输入一页论文的图像，直接输出带 LaTeX 数学公式与表格的标记文本。本文依据 arXiv v1 阅读。代码以 MIT 许可证开源，模型权重采用 CC BY-NC。\n\n## 定义问题\n\n当时已有的工具各有缺口：\n\n- **Tesseract** 这类 OCR 引擎擅长检测和分类单个字符或单词，但它逐行处理，看不懂上标、下标这类位置关系。\n- **GROBID** 能把原生数字论文 PDF 解析成 XML，书目信息处理得很好，数学公式却只保留 PDF 里的 Unicode 字符。\n- **pdf2htmlEX** 能把 PDF 转成外观一致的 HTML，但同样救不回数学公式的语义。\n\n作者想要的是一个只看页面图像的模型。只看图像，意味着扫描的旧论文和书籍也能处理；直接输出标记语言，意味着数学公式和表格的结构能保留下来。\n\n## 解决问题\n\n### 架构：沿用 Donut\n\n[![Nougat 架构：文档页面图像经 Swin Transformer 编码成潜在表示 z，再由 Transformer 解码器自回归地输出 token，右侧为输出的示例文本](/content/papers/assets/73888d5b579ab68d56551dc59d69ebcd0bf97704d288425f0341c9a9aa012138.png)](/content/papers/assets/73888d5b579ab68d56551dc59d69ebcd0bf97704d288425f0341c9a9aa012138.png)\n\n*原论文 Figure 1，取自 [**v1 PDF 第 2 页**](https://arxiv.org/pdf/2308.13418v1#page=2)，CC BY-SA 4.0。*\n\n架构很简单，沿用 2021 年的 Donut：\n\n1. **编码器**：页面先裁掉页边，缩放并填充到固定的 896×672（比例介于 US Letter 与 A4 之间），交给 Swin Transformer 转成一串 patch 向量 $z$。\n2. **解码器**：10 层的 mBART 解码器，用 cross-attention 读取 $z$，自回归地输出 token，最多 4,096 个。分词器借用了专门处理科学文本的 Galactica。\n\n整个模型约 3.5 亿参数。作者另外试了一个 2.5 亿参数的小版本，解码器只有 4 层。推理时用贪心解码。\n\n这里没有文本检测，也没有任何 OCR 预处理。字是怎么读出来的，全交给网络自己去学。\n\n### 数据：把 LaTeX 源码切成一页一页\n\n最大的工程量在数据上。要训练「页面图像 → 标记文本」，需要大量成对数据，而当时并没有现成的。\n\n作者从 arXiv 收集了 1,748,201 篇论文的 LaTeX 源码与编译好的 PDF，另外加入一部分 PubMed Central 的开放论文，预训练时再加上 Industry Documents Library 的 OCR 文本。\n\n处理流程是：\n\n1. 用 LaTeXML 把 LaTeX 转成 HTML，顺便展开自定义宏、统一空白、规范化表格、把引用替换成正确的编号。\n2. 把 HTML 转成一种轻量的标记语言，保留标题、粗体与斜体、算法、行内与独立的 LaTeX 数学公式、LaTeX 表格。\n3. 把整篇源码切成一页一页，与 PDF 每一页的图像对应起来。\n\n第三步最麻烦。LaTeX 的分页由编译器自己决定，源码里没有分页标记；图表在 PDF 里的位置，也常常和源码里不同。作者的做法分两步：\n\n- **粗切**：先用 MuPDF 提取 PDF 每一页的文本，训练一个 TF-IDF 加线性 SVM 的分类器，预测源码每一段属于第几页。理想情况下会得到一条阶梯状的页码序列；实际上噪声很大，所以再用类似决策树的 Gini 不纯度，找出最佳的分页点。\n- **细切**：在预测的分页点附近，拿源码和 PDF 上一页的最后几句、下一页的开头几句做模糊匹配，找出精确位置。两个分页点的平均分数要达到 0.9，这一页才收进数据集。\n\n最后约 47% 的页面通过了筛选。\n\n### 让数字 PDF 看起来像扫描件\n\n训练数据全是原生数字论文，模型却要处理扫描件。作者用 Albumentations 加了一系列图像扰动：腐蚀、膨胀、高斯噪声、模糊、二值化、压缩、网格畸变、弹性形变。\n\n另外，他们在**文本端**也加了扰动，后面会谈到这一步的作用。\n\n## 讨论\n\n### arXiv 测试集上的成绩\n\n| 方法 | 类别 | 编辑距离 ↓ | BLEU ↑ | F1 ↑ |\n| --- | --- | ---: | ---: | ---: |\n| PDF 内嵌文本 | 全部 | 0.255 | 65.8 | 79.2 |\n| GROBID | 全部 | 0.312 | 55.6 | 73.0 |\n| Nougat base | 全部 | 0.071 | 89.1 | 93.1 |\n| Nougat base | 普通文本 | 0.058 | 91.2 | 95.7 |\n| Nougat base | 数学公式 | 0.128 | 56.9 | 76.5 |\n| Nougat base | 表格 | 0.211 | 69.7 | 78.0 |\n\n*表：节选自原论文 Table 1。*\n\n整体来说，Nougat 的编辑距离只有 GROBID 的四分之一左右。三类内容里，数学公式最难，编辑距离是普通文本的两倍以上。\n\n作者解释，数学公式的分数天生会偏低：同一个公式在 LaTeX 里有很多种写法，例如上下标的先后、`\\frac` 与 `\\over`、`\\mathbf` 与 `\\boldsymbol`，渲染出来一模一样，字符串却不同。\n\n小模型（2.5 亿参数）和大模型的成绩几乎一样。\n\n### 陷入重复\n\n这篇论文最值得读的，是作者很坦白地记录了失败的样子。\n\n模型有时会陷入重复：最简单的情况是同一句、同一段一直输出；也可能在两句之间来回打转，每次换几个字，让严格的重复检测抓不到。参考文献部分甚至会出现模型自己数着编号一路往下写的情况。一旦进入这种状态，模型就回不来了。\n\n测试集上约 1.5% 的页面出现这种情况；训练领域以外的文档更常见。作者观察到，重复通常发生在模型犯了一个错之后。\n\n这就给出了解法的方向：**让模型在训练时就见过自己的错**。他们在训练时随机把一些正确的 token 换成任意 token，替换会一直进行，直到抽到的随机数大于 10% 为止。模型因此学会在前文有错时继续往下读，而不是被错字牵着走。作者说这没有降低整体表现，却明显减少了重复；在领域外的文档上，转换失败的页面减少了 32%。\n\n### 检测重复\n\n光是减少还不够。解码器最多要生成 4,096 个 token，一旦陷入重复，就得白白跑到上限。所以作者另外设计了检测方法。\n\n[![两组重复检测的例子，各三张图：每个 token 的最大 logit、滑动窗口方差、从该位置到结尾的方差。上排在约第 1,000 个 token 后陷入重复，方差骤降并低于阈值；下排是正常样本，方差一直保持在高位](/content/papers/assets/1a40149c71166aacbd2c464be00126a4ae00240e18bac1afb5a04502192d89a2.png)](/content/papers/assets/1a40149c71166aacbd2c464be00126a4ae00240e18bac1afb5a04502192d89a2.png)\n\n*原论文 Figure 6，取自 [**v1 PDF 第 8 页**](https://arxiv.org/pdf/2308.13418v1#page=8)，CC BY-SA 4.0。上排为出现重复的样本，下排为正常样本；虚线分别是重复开始的位置与判断阈值。*\n\n先看上排最左边：横轴是生成到第几个 token，纵轴是每一步的最大 logit。大约在第 1,000 个 token 之前，点散得很开；之后全部挤在 17 到 18 之间的一条窄带上。下排的正常样本则一直散得很开。\n\n直觉上，正常文本每一步的把握程度有高有低；陷入重复时，模型对下一个 token 越来越笃定，最大 logit 就平了下来。作者把它变成两步计算：\n\n1. 对最大 logit 序列 $\\ell$ 取大小为 $B=15$ 的滑动窗口，算出每个窗口内的方差 $\\mathrm{VarWin}_B$（中间那张图）。\n2. 再从每个位置到序列结尾，计算这些方差的方差 $\\mathrm{VarEnd}_B$（右边那张图）。\n\n如果 $\\mathrm{VarEnd}_B$ 降到 6.75 以下，并且一直保持到结尾，就判定为重复。\n\n拿三个数字感受一下（示意数字，不是论文数据）：正常的一段，最大 logit 是 20、25、18，方差约 8.67；重复时是 17.0、17.2、16.9，方差只有 0.016。差了好几百倍，很好区分。\n\n推理时还看不到「结尾」，所以作者只取最近 200 个 token，阈值减半，边生成边判断；生成结束后再用完整序列算一次。\n\n### 社区的实际经验\n\nNougat 的 GitHub 上，第 11 号 issue 是 2023 年 8 月 30 日的一条反馈：用户拿 1935 年 Physical Review 上的 EPR 论文扫描件测试，第一页正常，第二到四页都出现「Found repetitions」警告，输出只剩 `[MISSING_PAGE_EMPTY:1]`。[facebookresearch/nougat#11](https://github.com/facebookresearch/nougat/issues/11)\n\n这正是重复检测在起作用：判定失败的页面被标成缺页，而不是输出一页重复的文字。对用户来说，看到缺页标记，至少知道这一页要另外处理。\n\n官方 README 也直接写明了语言范围：英文论文效果最好，其他使用拉丁字母的语言也许可以，中文、俄文、日文等则不行。\n\n### 读这篇时要知道的事\n\n作者在局限性一节列了几点：\n\n1. **重复仍是最大的问题**，论文把它留给了未来的工作。\n2. **几乎只支持英文**。其他拉丁字母语言的特殊字符会被换成最接近的英文字母；非拉丁文字会立刻陷入重复。\n3. **一次只看一页**。跨页的一致性没有保证，最明显的是参考文献：编号有时会跳号，或者多出原文没有的编号。\n4. **很慢**。在一张 A10G 上一次处理 6 页，平均每批 19.5 秒；GROBID 每秒可以处理 10.6 份 PDF。\n\n## 结论\n\nNougat 把学术论文的 OCR 改写成「看一页、写一页标记文本」的生成任务：\n\n1. **架构简单**：Swin Transformer 编码器加 mBART 解码器，没有 OCR 预处理。\n2. **数据工程是主角**：从 175 万篇 arXiv 论文的 LaTeX 源码出发，靠分类器与模糊匹配切出逐页的训练数据。\n3. **数学公式第一次能被端到端地读成 LaTeX**，整体编辑距离比 GROBID 低得多。\n\n它也很早就把生成式 OCR 的典型毛病摊开来：陷入重复、把少见的字符换成常见的字母、替参考文献补上不存在的编号。作者没有只报成绩，还给出了对策：训练时注入错误，推理时检测重复。\n\n一页字一旦交给语言模型来「写」，它就会尽量写得通顺。写不下去的时候，最好让它停下来，而不是一直写下去。\n","imageSizes":{"/content/papers/assets/73888d5b579ab68d56551dc59d69ebcd0bf97704d288425f0341c9a9aa012138.png":{"width":1283,"height":288},"/content/papers/assets/1a40149c71166aacbd2c464be00126a4ae00240e18bac1afb5a04502192d89a2.png":{"width":1233,"height":800}}}
