{"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-hant","path":"/content/papers/zh-hant/text-spotting/nougat.b9ad81f9f234.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}}}
