Dolphin文檔解析從理論到實踐——保姆級教程

在這里插入圖片描述
論文:https://arxiv.org/abs/2505.14059
代碼:github.com/bytedance/Dolphin
2025年5月,字節開源了文檔解析Dolphin,讓文檔解析效率提升83%。本文將深入解析字節跳動最新開源的Dolphin模型,先看理論再實戰體驗。

現實世界中約80%的有價值信息都被"囚禁"在非結構化文檔中——PDF學術論文、企業報告、技術文檔、醫療記錄。這些"沉睡的數據資產"如同被鎖在保險柜中的黃金,等待著被解放的鑰匙。

一. 理論

1. 文檔解析面臨的挑戰

文檔解析表面上看似直觀——將圖像轉換為可編輯文本。但深入分析后發現,這是一個涉及計算機視覺、自然語言處理、布局分析、結構理解的多維度挑戰:

  • 視覺復雜性:從手寫筆記到精美排版,從單欄文本到多欄布局
  • 內容異構性:文本、表格、公式、圖表、化學結構式的混合出現
  • 結構層次性:標題、段落、列表、腳注的層次關系
  • 語言多樣性:多語言混排、專業術語、數學符號
  • 質量差異性:掃描質量、拍照角度、光照條件的不一致

2. 目前的解決方案

傳統路徑:集成式專家系統——通過不同的算法模塊組合和邏輯策略實現文檔解析(例如Paddle OCR),技術框架如下圖所示。
在這里插入圖片描述

多個模型組合實現文檔解析

優勢:每個專家模型在特定任務上精度較高

缺點如下

  • 錯誤累積效應:前一階段的錯誤會被放大傳遞
  • 系統復雜度高:需要維護多個模型和復雜的協調機制
  • 結構丟失風險:在模型間傳遞過程中容易丟失全局結構信息
  • 效率瓶頸:串行處理導致延遲累積

多模態視覺-語言大模型解決方案,以Qwen2.5 VL、GPT-4V為代表,采取一步到位的策略,實現路徑如下圖所示。
在這里插入圖片描述

視覺-語言多模態大模型實現文檔解析

優勢:架構簡潔,能夠利用大模型的泛化能力

缺點如下

  • 效率困境:自回歸解碼的串行特性導致處理速度慢
  • 結構丟失:長序列生成過程中容易丟失布局信息
  • 資源消耗:需要大規模模型才能達到可用精度
  • 控制困難:難以精確控制輸出格式和結構

3. Dolphin是如何實現的?

在這里插入圖片描述

  • Dolphin模型以322M的輕量級參數量,在所有評測指標上都取得了最優性能
  • 處理效率方面,Dolphin達到0.1729 FPS,比第二名Mathpix(0.0944 FPS)快近2倍
  • 相比動輒數千億參數的通用VLM和復雜的集成式方案,Dolphin在保持輕量化的同時實現了專業文檔解析的最佳效果

那么Dolphin是如何實現的呢?下圖展示了Dolphin的算法架構:
在這里插入圖片描述

Dolphin算法框架:包含布局分析模塊和并行解析模塊

布局分析模塊:確定自然閱讀順序、識別元素塊類別、檢測元素塊的bbox,元素塊包括:段落、表格、圖片、公式等。

# 偽代碼示例
def stage1_layout_analysis(document_image):visual_features = swin_transformer(document_image)layout_prompt = "Parse the reading order of this document."layout_sequence = mbart_decoder(visual_features, layout_prompt)return structured_elements  # [(type, bbox, reading_order), ...]

元素內容解析模塊:根據元素的類別對應不同的提示詞,并對元素塊進行并行解析,從而實現元素級別的內容識別。

# 偽代碼示例
def stage2_content_parsing(document_image, layout_elements):results = []for element in layout_elements:cropped_region = crop_image(document_image, element.bbox)task_prompt = get_prompt_by_type(element.type)content = mbart_decoder(cropped_region, task_prompt)results.append((element, content))return parallel_process(results)  # 并行處理

4. Dolphin設計亮點

共享編解碼器,同一個模型實現布局分析模塊和元素內容解析模塊。僅通過提示詞差異化實現功能分化,如下表所示:
在這里插入圖片描述

PROMPTS = {"layout": "Parse the reading order of this document.","table": "Extract table structure and content in HTML format.","paragraph": "Extract text content preserving structure.","formula": "Convert mathematical formula to LaTeX format."
}

元素塊并行解析,實現效率的提升

二. 實踐

1. 獲取代碼并配置環境

# 獲取代碼
git clone https://github.com/ByteDance/Dolphin.git
cd Dolphin# 配置環境
pip install -r requirements.txt

2. 下載模型并測試

模型下載地址:https://drive.google.com/drive/folders/1PQJ3UutepXvunizZEw-uGaQ0BCzf-mie
下載的模型放在./checkpoints目錄下
測試代碼腳本:

python demo_page.py --config ./config/Dolphin.yaml --input_path ./demo/page_imgs/page_1.jpeg --save_dir ./results

3. 結果可視化

# 更多精彩,請關注微信公眾號:AIWorkshopLab
import json
from PIL import Image, ImageDraw, ImageFont
import osdef draw_layout_on_image(img_path, layout_json_path, output_path):"""在圖片上繪制layout信息Args:img_path: 圖片路徑layout_json_path: layout.json文件路徑output_path: 輸出圖片路徑"""# 1. 用PIL讀取圖片img = Image.open(img_path)draw = ImageDraw.Draw(img)# 2. 讀取layout.json數據with open(layout_json_path, 'r', encoding='utf-8') as f:layout_data = json.load(f)# 定義不同label的顏色label_colors = {'tab': '#FF0000',      # 紅色 - 表格'cap': '#00FF00',      # 綠色 - 標題'sec': '#0000FF',      # 藍色 - 章節'para': '#FF00FF',     # 紫色 - 段落'pic': '#FFFF00',      # 黃色 - 圖片'fig': '#FFFF00',      # 黃色 - 圖片'list': '#00FFFF',     # 青色 - 列表'formula': '#FFA500',  # 橙色 - 公式'footnote': '#800080', # 紫紅色 - 腳注'header': '#008000',   # 深綠色 - 頁眉'footer': '#800000'    # 深紅色 - 頁腳}# 嘗試加載支持中文的字體font_large = Nonefont_small = None# 常見的中文字體路徑列表chinese_font_paths = ["/usr/share/fonts/truetype/wqy/wqy-microhei.ttc","/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc", "/usr/share/fonts/truetype/arphic/ukai.ttc","/usr/share/fonts/truetype/arphic/uming.ttc"]# 嘗試加載中文字體for font_path in chinese_font_paths:try:if os.path.exists(font_path):font_large = ImageFont.truetype(font_path, 16)font_small = ImageFont.truetype(font_path, 12)print(f"成功加載字體: {font_path}")breakexcept Exception as e:continue# 如果沒有找到中文字體,嘗試使用英文字體if font_large is None:try:font_large = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16)font_small = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 12)print("使用英文字體")except:print("警告: 無法加載任何字體,將使用基本繪制方式")def safe_text_length(text, font):"""安全地計算文本長度,處理編碼錯誤"""try:if font:return draw.textlength(text, font=font)else:# 簡單估算:中文字符按2個字符寬度,英文按1個字符寬度chinese_chars = sum(1 for char in text if ord(char) > 127)english_chars = len(text) - chinese_charsreturn chinese_chars * 12 + english_chars * 6  # 估算寬度except UnicodeEncodeError:# 如果遇到編碼錯誤,使用簡單估算chinese_chars = sum(1 for char in text if ord(char) > 127)english_chars = len(text) - chinese_charsreturn chinese_chars * 12 + english_chars * 6def safe_draw_text(x, y, text, fill, font=None):"""安全地繪制文本,處理編碼錯誤"""try:if font:draw.text((x, y), text, fill=fill, font=font)else:draw.text((x, y), text, fill=fill)except UnicodeEncodeError:# 如果遇到編碼錯誤,嘗試只繪制ASCII字符ascii_text = ''.join(char if ord(char) < 128 else '?' for char in text)draw.text((x, y), ascii_text, fill=fill, font=font if font else None)# 3. 遍歷layout數據并繪制for item in layout_data:label = item['label']bbox = item['bbox']  # [x1, y1, x2, y2]reading_order = item['reading_order']text = item.get('text', '')# 獲取顏色,如果沒有定義則使用默認顏色color = label_colors.get(label, '#808080')# 繪制邊界框draw.rectangle(bbox, outline=color, width=3)# 繪制label和reading_orderlabel_text = f"{label}({reading_order})"# 計算文本位置(在框的左上角)text_x = bbox[0]text_y = bbox[1] - 20 if bbox[1] > 20 else bbox[1] + 5# 繪制背景矩形使文字更清晰try:if font_large:text_bbox = draw.textbbox((text_x, text_y), label_text, font=font_large)draw.rectangle(text_bbox, fill='white', outline=color)safe_draw_text(text_x, text_y, label_text, color, font_large)except:# 如果出錯,使用簡單方式繪制safe_draw_text(text_x, text_y, label_text, color)# 如果文本內容不為空且不是表格HTML,顯示部分文本內容if text and not text.startswith('<table>'):# 截取前30個字符避免文本過長(中文字符較寬)display_text = text[:30] + "..." if len(text) > 30 else textdisplay_text = display_text.replace('\n', ' ')  # 替換換行符# 在框內顯示文本內容content_x = bbox[0] + 5content_y = bbox[1] + 25# 簡化文本處理,避免復雜的換行邏輯導致編碼錯誤if font_small:# 計算可用寬度available_width = bbox[2] - bbox[0] - 10# 簡單的文本截斷,避免復雜的分詞邏輯max_chars = max(1, available_width // 8)  # 估算每個字符8像素寬度if len(display_text) > max_chars:display_text = display_text[:max_chars] + "..."# 繪制文本if content_y < bbox[3] - 15:  # 確保不超出框的底部safe_draw_text(content_x, content_y, display_text, 'black', font_small)else:safe_draw_text(content_x, content_y, display_text, 'black')# 4. 保存結果img.save(output_path)print(f"結果已保存到: {output_path}")def main():# 設置文件路徑img_path = "./test.png"layout_json_path = "./results/recognition_json/test.json"output_path = "./test_visualization.png"# 檢查文件是否存在if not os.path.exists(img_path):print(f"圖片文件不存在: {img_path}")returnif not os.path.exists(layout_json_path):print(f"JSON文件不存在: {layout_json_path}")return# 創建輸出目錄(如果輸出路徑包含目錄)output_dir = os.path.dirname(output_path)if output_dir:os.makedirs(output_dir, exist_ok=True)# 執行繪制draw_layout_on_image(img_path, layout_json_path, output_path)if __name__ == "__main__":main()

測試結果如下,左圖是輸入圖片,右圖是可視化結果。
在這里插入圖片描述
博主思考:Dolphin在文檔解析精度和解析效率達到了SOTA,代碼架構簡單,是未來的發展趨勢。雖然在復雜板式和豎排文字識別上還有些問題,但是通過添加數據并適當加大模型應該是可以解決的。

感謝關注,喜歡記得給博主點贊~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/907492.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/907492.shtml
英文地址,請注明出處:http://en.pswp.cn/news/907492.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Web3怎么本地測試連接以太坊?

ETHEREUM_RPC_URLhttps://sepolia.infura.io/v3/你的_INFURA_API_KEY 如果你沒有 Infura Key&#xff0c;注冊 Infura 或 Alchemy&#xff0c;拿一個免費測試網節點就行&#xff1a; Infura&#xff1a;https://infura.io Alchemy&#xff1a;Alchemy - the web3 developme…

深化生態協同,寧盾身份域管完成與拓波軟件兼容互認證

在信創產業蓬勃發展的浪潮下&#xff0c;行業生態的兼容適配決定了信創產品是否好用。近日&#xff0c;寧盾身份域管與拓波軟件 TurboEX 郵件系統完成兼容互認證。測試結果顯示寧盾身份域管&#xff08;信創版&#xff09;與 TurboEX 郵件服務器軟件相互良好兼容&#xff0c;運…

HDFS存儲原理與MapReduce計算模型

HDFS存儲原理 1. 架構設計 主從架構&#xff1a;包含一個NameNode&#xff08;主節點&#xff09;和多個DataNode&#xff08;從節點&#xff09;。 NameNode&#xff1a;管理元數據&#xff08;文件目錄結構、文件塊映射、塊位置信息&#xff09;&#xff0c;不存儲實際數據…

Function calling的過程

文章目錄 逐段講清 **LLM Function Calling&#xff08;函數調用&#xff09;** 的典型鏈路。1. 角色與概念 | Actors & Concepts2. 全流程時序 | End-to-End Sequence3. 關鍵細節 | Key Implementation Notes4. 最小可用示例&#xff08;偽代碼&#xff09; | Minimal Exa…

GlobalExceptionHandler 自定義異常類 + 處理validation的異常

在 Spring Boot 項目中&#xff0c;?自定義異常通常用于處理特定的業務邏輯錯誤&#xff0c;并結合全局異常處理器&#xff08;ControllerAdvice&#xff09;統一返回結構化的錯誤信息。 一.全局異常處理器&#xff1a; 1. 自定義異常類? 定義一個繼承自 RuntimeExceptio…

軟件測試過程中如何定位BUG

在軟件測試過程中&#xff0c;定位BUG是確保軟件質量的關鍵環節。有效的BUG定位不僅能幫助開發人員快速修復問題&#xff0c;還能提升整個軟件項目的效率。以下是軟件測試中定位BUG的系統性方法和策略&#xff1a; 一、復現BUG 步驟&#xff1a; 收集信息&#xff1a;記錄BUG…

如何優化Elasticsearch的搜索性能?

優化 Elasticsearch 的搜索性能需要從索引設計、查詢優化、硬件配置和集群調優等多方面入手。以下是系統化的優化策略和實操建議: 一、索引設計優化 1. 合理設置分片數 分片大小:單個分片建議 10-50GB(超過50GB會影響查詢性能)。分片數量: 總分片數 ≤ 節點數 1000(避免…

臺式電腦CPU天梯圖_2025年臺式電腦CPU天梯圖

CPU的選擇絕對是重中之重,它關乎了一臺電腦性能好壞。相信不少用戶,在挑選CPU的時候不知道誰強誰弱,尤其是intel和AMD兩款CPU之間。下面通過2025年臺式電腦CPU天梯圖來了解下這兩款cpu. 2025年臺式電腦CPU天梯圖 2025年臺式電腦CPU天梯圖包含了老舊型號以及12代、13代、14代…

HarmonyOS_ArkTs_API(1)

HarmonyOS_ArkTs_API(1) 概述 此API服務模塊是獨自開發的應用程序的核心骨架&#xff0c;提供了鴻蒙OS ArkTS客戶端組件和Java Spring Boot后端之間的強大通信接口。該模塊采用清晰的架構方法處理所有HTTP請求、響應解析和錯誤處理&#xff0c;確保系統各部分間通信的一致性和…

matlab雷達定位仿真

一、邊掃描邊跟蹤雷達仿真 邊掃描邊跟蹤&#xff08;BISTAR&#xff09;雷達仿真是一種實時雷達信號處理的技術&#xff0c;用于模擬雷達系統的操作過程&#xff0c;特別是那些具備連續掃描能力的雷達。它的基本原理和流程可以分為以下幾個步驟&#xff1a; &#xff08;1&…

互斥鎖、自旋鎖、讀寫鎖、悲觀鎖、樂觀鎖的應用場景

一&#xff1a;并發 1.1MySQL并發事務訪問相同記錄 &#xff08;1&#xff09;讀-讀 不影響 &#xff08;2&#xff09;寫-寫 寫的數據需要一個一個來&#xff0c;排隊執行 &#xff08;3&#xff09;讀-寫 兩次讀…

KEYSIGHT N9320B是德科技N9320B頻譜分析儀

KEYSIGHT N9320B是德科技N9320B頻譜分析儀 附加功能&#xff1a; 頻率范圍&#xff1a;9 kHz 至 3 GHz 分辨率帶寬&#xff1a;10 Hz 至 1 MHz DANL&#xff1a;-130 dBm&#xff0c;-148 dBm&#xff0c;帶可選前置放大器 整體幅度精度&#xff1a;<1.5 dB 最小非零掃…

零基礎開始的網工之路第十四天------Linux程序管理

目錄 一、Linux程序與進程 1、程序,進程,線程的概念 2、程序和進程的區別 3、進程和線程的區別 二、Linux進程基礎(生命周期) 1、進程生命周期 2、父子進程的關系 三、程序管理 1、常見的軟件包類型 四、Linux操作系統啟動流程詳解 1、概述 2、啟動流程核心階段 1…

群輝(synology)NAS老機器連接出現網頁端可以進入,但是本地訪問輸入一樣的賬號密碼是出現錯誤時解決方案

群輝&#xff08;synology&#xff09;NAS老機器連接出現網頁端可以進入&#xff0c;但是本地訪問輸入一樣的賬號密碼是出現錯誤時解決方案 老機器 裝的win7 系統 登入后端網頁端的時候正常&#xff0c;但是本地訪問登入時輸入登入網頁端一樣的密碼時候出現問題解決方案 1.登…

單例模式的隱秘危機

引言 單例模式作為設計模式中的基石&#xff0c;廣泛應用于配置管理、線程池、緩存系統等關鍵場景。然而&#xff0c;許多開發者誤以為“私有構造函數”足以保障其唯一性&#xff0c;卻忽視了反射機制、對象克隆、序列化反序列化這三把“隱形利刃”——它們能繞過常規防御&…

DMBOK對比知識點對比(3)

1.數據倉庫建設方法(Inmon、Kimball) 數據倉庫建設方法(Inmon、Kimball)P293方法

Python+VR:如何讓虛擬世界更懂你?——用戶行為分析的實踐

友友們好! 我是Echo_Wish,我的的新專欄《Python進階》以及《Python!實戰!》正式啟動啦!這是專為那些渴望提升Python技能的朋友們量身打造的專欄,無論你是已經有一定基礎的開發者,還是希望深入挖掘Python潛力的愛好者,這里都將是你不可錯過的寶藏。 在這個專欄中,你將會…

游戲引擎學習第311天:支持手動排序

倉庫: https://gitee.com/mrxiao_com/2d_game_7(已滿) 新倉庫: https://gitee.com/mrxiao_com/2d_game_8 回顧并為今天的內容定下基調 我們接下來要繼續完成之前開始的工作&#xff0c;上周五開始的部分內容&#xff0c;雖然當時對最終效果還不太確定&#xff0c;但現在主要任…

數據結構第2章緒論 (竟成)

第 2 章 緒論 本章主要介紹數據結構相關的一些基本概念&#xff0c;是后續章節的基礎。我們也將 408 考試大綱中&#xff0c;關于數據結構部分的考查目標羅列在這里&#xff0c;供各位考生參考&#xff1a; 1.掌握數據結構的基本概念、基本原理和基本方法。 2.掌握數據的邏輯結…

spring boot 攔截器HandlerInterceptor 不生效的原因排查

public class UserInterceptor implements HandlerInterceptor項目添加一個攔截器&#xff0c;發現未生效 1、排查攔截本身是否注入了springbean 容器 Slf4j Component public class LoginInterceptor implements HandlerInterceptor {2、排查springboot 項目掃描范圍是否包含…