mineru_处理流程.md 15 KB

正在收集工作区信息正在筛选到最相关的信息根据 demo.py 的代码分析,我来生成 MinerU 的处理流程图:

1. MinerU 处理流程图

graph TB
    Start([开始: 输入PDF/图片文件]) --> ReadFile[read_fn: 读取文件字节]
    ReadFile --> CheckBackend{选择后端?}
    
    %% Pipeline 后端流程
    CheckBackend -->|backend=pipeline| ConvertPDF1[convert_pdf_bytes_to_bytes_by_pypdfium2<br/>转换PDF字节流]
    ConvertPDF1 --> PipelineAnalyze[pipeline_doc_analyze<br/>批量分析文档]
    
    PipelineAnalyze --> CheckMethod{检查解析方法}
    CheckMethod -->|parse_method=auto| Classify[classify模型<br/>PDF分类: txt/ocr]
    CheckMethod -->|parse_method=txt| SetTxt[设置txt模式]
    CheckMethod -->|parse_method=ocr| SetOcr[设置ocr模式]
    
    Classify --> PDFType{PDF类型?}
    SetTxt --> LoadImages1
    SetOcr --> LoadImages1
    
    PDFType -->|文字PDF txt模式| LoadImages1[load_images_from_pdf<br/>加载PDF页面图像<br/>data: images_list, pdf_doc]
    PDFType -->|图片PDF ocr模式| LoadImages1
    
    LoadImages1 --> BatchInfer[batch_image_analyze<br/>批量推理]
    
    BatchInfer --> LayoutModel[布局检测模型<br/>MinerU Layout Detection]
    LayoutModel --> LayoutResult[layout_det结果<br/>检测文本/表格/图片区域]
    
    LayoutResult --> OCRBranch{需要OCR?}
    OCRBranch -->|txt模式: 文字PDF| ExtractText[提取嵌入文本<br/>直接读取PDF文本层]
    OCRBranch -->|ocr模式: 图片PDF| OCRModel[OCR识别模型<br/>PaddleOCR/Surya]
    
    ExtractText --> MergeText[文本合并]
    OCRModel --> OCRResult[OCR识别结果<br/>文本块坐标+内容]
    OCRResult --> MergeText
    
    MergeText --> FormulaCheck{公式识别?}
    FormulaCheck -->|formula_enable=True| FormulaModel[公式识别模型<br/>UniMERNet]
    FormulaCheck -->|formula_enable=False| TableCheck
    FormulaModel --> FormulaResult[公式LaTeX结果]
    FormulaResult --> TableCheck
    
    TableCheck{表格识别?}
    TableCheck -->|table_enable=True| TableModel[表格识别模型<br/>StructEqTable]
    TableCheck -->|table_enable=False| ModelList
    TableModel --> TableResult[表格HTML结果]
    TableResult --> ModelList
    
    ModelList[生成model_list<br/>原始模型输出JSON] --> ToMiddleJson[pipeline_result_to_middle_json<br/>转换为中间JSON格式]
    
    ToMiddleJson --> MiddleJson[middle_json<br/>包含pdf_info数组]
    MiddleJson --> ProcessOutput1[_process_output<br/>处理输出]
    
    %% VLM 后端流程
    CheckBackend -->|backend=vlm-xxx| ConvertPDF2[convert_pdf_bytes_to_bytes_by_pypdfium2<br/>转换PDF字节流]
    ConvertPDF2 --> VLMAnalyze[vlm_doc_analyze<br/>VLM端到端分析]
    
    VLMAnalyze --> CheckVLMBackend{VLM后端类型?}
    CheckVLMBackend -->|transformers| VLMTransformers[加载本地VLM模型<br/>MinerU-VLM/MinerU2.5-2509-1.2B]
    CheckVLMBackend -->|vllm-engine| VLMEngine[vLLM引擎<br/>本地GPU推理]
    CheckVLMBackend -->|http-client| VLMClient[HTTP客户端<br/>连接远程vLLM服务器]
    
    VLMTransformers --> VLMInfer[VLM模型推理<br/>输入: PDF图像<br/>输出: 结构化JSON]
    VLMEngine --> VLMInfer
    VLMClient --> HTTPRequest[发送HTTP请求<br/>server_url]
    HTTPRequest --> VLMInfer
    
    VLMInfer --> VLMResult[VLM输出结果<br/>直接生成结构化内容]
    VLMResult --> VLMMiddleJson[result_to_middle_json<br/>转换为middle_json格式]
    VLMMiddleJson --> ProcessOutput2[_process_output<br/>处理输出]
    
    %% 输出处理流程
    ProcessOutput1 --> DrawLayout{绘制布局框?}
    ProcessOutput2 --> DrawLayout
    
    DrawLayout -->|f_draw_layout_bbox=True| DrawLayoutPDF[draw_layout_bbox<br/>生成layout.pdf]
    DrawLayout -->|False| DrawSpan
    DrawLayoutPDF --> DrawSpan
    
    DrawSpan{绘制span框?}
    DrawSpan -->|f_draw_span_bbox=True| DrawSpanPDF[draw_span_bbox<br/>生成span.pdf]
    DrawSpan -->|False| MakeMarkdown
    DrawSpanPDF --> MakeMarkdown
    
    MakeMarkdown{生成Markdown?}
    MakeMarkdown -->|f_dump_md=True| UnionMake1[pipeline_union_make 或<br/>vlm_union_make]
    MakeMarkdown -->|False| ContentList
    
    UnionMake1 --> MarkdownFile[输出: xxx.md<br/>包含文本/公式/表格/图片]
    MarkdownFile --> ContentList
    
    ContentList{生成内容列表?}
    ContentList -->|f_dump_content_list=True| UnionMake2[union_make<br/>MakeMode.CONTENT_LIST]
    ContentList -->|False| MiddleJsonOut
    UnionMake2 --> ContentListFile[输出: xxx_content_list.json<br/>结构化内容列表]
    ContentListFile --> MiddleJsonOut
    
    MiddleJsonOut{保存中间JSON?}
    MiddleJsonOut -->|f_dump_middle_json=True| MiddleJsonFile[输出: xxx_middle.json<br/>中间处理结果]
    MiddleJsonOut -->|False| ModelOut
    MiddleJsonFile --> ModelOut
    
    ModelOut{保存模型输出?}
    ModelOut -->|f_dump_model_output=True| ModelFile[输出: xxx_model.json<br/>原始模型输出]
    ModelOut -->|False| End
    ModelFile --> End([结束: 所有文件保存到output_dir])
    
    %% 样式定义
    classDef modelClass fill:#e1f5ff,stroke:#01579b,stroke-width:2px
    classDef dataClass fill:#fff3e0,stroke:#e65100,stroke-width:2px
    classDef processClass fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
    
    class LayoutModel,OCRModel,FormulaModel,TableModel,VLMTransformers,VLMEngine,Classify modelClass
    class LayoutResult,OCRResult,FormulaResult,TableResult,ModelList,MiddleJson,VLMResult dataClass
    class PipelineAnalyze,VLMAnalyze,ToMiddleJson,VLMMiddleJson,ProcessOutput1,ProcessOutput2 processClass

关键差异说明

1. 文字PDF (txt模式) vs 图片PDF (ocr模式)

维度 文字PDF (txt模式) 图片PDF (ocr模式)
检测方式 classify 模型自动判断 手动指定或分类识别
文本提取 直接读取PDF嵌入的文本层 使用OCR模型识别图像中的文字
处理速度 快速(无需OCR) 较慢(需要OCR推理)
准确性 高(原生文本) 取决于OCR模型质量
典型场景 Word转PDF、电子书 扫描件、截图PDF

2. Pipeline vs VLM 后端差异

特性 Pipeline后端 VLM后端
模型架构 多个专用模型(Layout+OCR+公式+表格) 单一端到端VLM模型
处理流程 分步骤处理,每步调用不同模型 一次性输出结构化结果
优势 可控性强,每步可优化 简化流程,理解能力强
劣势 流程复杂,错误累积 需要大模型支持
适用场景 通用文档解析 复杂布局/多语言混排

3. 关键数据流

# Pipeline模式数据流
PDF字节流 → 图像列表(images_list) → 模型推理(model_list) → 中间JSON(middle_json) → Markdown

# VLM模式数据流
PDF字节流 → 图像列表 → VLM推理(infer_result) → 中间JSON(middle_json) → Markdown

4. 输出文件说明

  • xxx.md: 最终Markdown文档
  • xxx_content_list.json: 结构化内容列表(用于程序化处理)
  • xxx_middle.json: 中间处理结果(包含完整的pdf_info数组)
  • xxx_model.json: 原始模型输出(用于调试)
  • xxx_layout.pdf: 布局可视化(标注文本/表格/图片区域)
  • xxx_span.pdf: span级别可视化(标注每个文本块)

2. PaddleOCR 模型架构分析

[10.192.72.11:~/models/modelscope_cache/models/OpenDataLab/PDF-Extract-Kit-1___0/models]$ find .
.
./MFR
./MFR/unimernet_hf_small_2503
./MFR/unimernet_hf_small_2503/config.json
./MFR/unimernet_hf_small_2503/model.safetensors
./MFR/unimernet_hf_small_2503/README.md
./MFR/unimernet_hf_small_2503/tokenizer_config.json
./MFR/unimernet_hf_small_2503/tokenizer.json
./MFR/unimernet_hf_small_2503/special_tokens_map.json
./MFR/unimernet_hf_small_2503/generation_config.json
./TabRec
./TabRec/UnetStructure
./TabRec/UnetStructure/unet.onnx
./TabRec/SlanetPlus
./TabRec/SlanetPlus/slanet-plus.onnx
./ReadingOrder
./ReadingOrder/layout_reader
./ReadingOrder/layout_reader/config.json
./ReadingOrder/layout_reader/model.safetensors
./OCR
./OCR/paddleocr_torch
./OCR/paddleocr_torch/latin_PP-OCRv5_rec_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv3_det_infer.pth
./OCR/paddleocr_torch/en_PP-OCRv3_det_infer.pth
./OCR/paddleocr_torch/te_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv4_det_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv5_rec_server_infer.pth
./OCR/paddleocr_torch/en_PP-OCRv4_rec_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv4_rec_server_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv5_rec_infer.pth
./OCR/paddleocr_torch/korean_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/korean_PP-OCRv5_rec_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv4_rec_server_doc_infer.pth
./OCR/paddleocr_torch/en_PP-OCRv5_rec_infer.pth
./OCR/paddleocr_torch/ch_ptocr_mobile_v2.0_cls_infer.pth
./OCR/paddleocr_torch/th_PP-OCRv5_rec_infer.pth
./OCR/paddleocr_torch/latin_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/el_PP-OCRv5_rec_infer.pth
./OCR/paddleocr_torch/Multilingual_PP-OCRv3_det_infer.pth
./OCR/paddleocr_torch/arabic_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv4_rec_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv5_det_infer.pth
./OCR/paddleocr_torch/devanagari_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/eslav_PP-OCRv5_rec_infer.pth
./OCR/paddleocr_torch/ta_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/cyrillic_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/ka_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/chinese_cht_PP-OCRv3_rec_infer.pth
./OCR/paddleocr_torch/japan_PP-OCRv3_rec_infer.pth
./TabCls
./TabCls/paddle_table_cls
./TabCls/paddle_table_cls/PP-LCNet_x1_0_table_cls.onnx
./Layout
./Layout/YOLO
./Layout/YOLO/doclayout_yolo_docstructbench_imgsz1280_2501.pt
./OriCls
./OriCls/paddle_orientation_classification
./OriCls/paddle_orientation_classification/PP-LCNet_x1_0_doc_ori.onnx
./MFD
./MFD/YOLO
./MFD/YOLO/yolo_v8_ft.pt

# mineru调用的paddle模型是已经什么架构?是pytouch还是paddle自有文件格式,转换了吗?

1. 模型文件格式

从文件列表可以看到:

./OCR/paddleocr_torch/ch_PP-OCRv4_det_infer.pth
./OCR/paddleocr_torch/ch_PP-OCRv5_rec_infer.pth
# ... 等等

关键发现

  • ✅ 文件扩展名是 .pth (PyTorch 格式)
  • ✅ 目录名是 paddleocr_torch(明确标注了 torch)
  • ✅ 这些是已经转换为 PyTorch 格式的模型

2. 原始 Paddle 模型转换

查看 MinerU 的模型加载代码:

# mineru/model/ocr_rec/paddleocr_rec/paddleocr_rec.py
class RecPaddleOCRX:
    def __init__(self, rec_model_path, lang=None):
        # 加载 PyTorch 模型
        self.model = torch.jit.load(rec_model_path)  # 或者直接 torch.load

3. 转换流程说明

MinerU 使用的是 Paddle2ONNX → PyTorch直接转换到 PyTorch 的模型:

graph LR
    A[原始 PaddlePaddle 模型<br/>.pdparams + .pdmodel] --> B{转换方式}
    
    B -->|方式1| C[Paddle2ONNX<br/>转换为 .onnx]
    B -->|方式2| D[paddle2torch<br/>直接转 PyTorch]
    
    C --> E[ONNX Runtime<br/>推理]
    C --> F[ONNX → PyTorch<br/>转换为 .pth]
    
    D --> G[PyTorch 模型<br/>.pth 文件]
    F --> G
    
    G --> H[MinerU 使用<br/>torch.load/jit.load]
    E --> I[MinerU 使用<br/>onnxruntime]
    
    style A fill:#ffe0b2
    style G fill:#c8e6c9
    style H fill:#bbdefb

4. 实际使用的模型格式对比

模型类型 原始格式 MinerU 使用格式 推理引擎
OCR .pdparams .pth (PyTorch) PyTorch
表格分类 .pdparams .onnx ONNX Runtime
方向分类 .pdparams .onnx ONNX Runtime
Layout检测 - .pt (YOLO原生) PyTorch
公式识别 - .safetensors PyTorch

5. 代码验证

查看 paddleocr_rec.py:

class RecPaddleOCRX:
    def __init__(self, rec_model_path, ...):
        # 加载 PyTorch 格式的模型
        if rec_model_path.endswith('.pth'):
            # PyTorch JIT 格式
            self.model = torch.jit.load(rec_model_path, map_location=self.device)
        else:
            # 标准 PyTorch 格式
            checkpoint = torch.load(rec_model_path, map_location=self.device)
            self.model.load_state_dict(checkpoint)

查看 paddleocr_det.py:

class DetPaddleOCRX:
    def __init__(self, det_model_path, ...):
        # 同样加载 PyTorch 格式
        self.model = torch.jit.load(det_model_path, map_location=self.device)

6. ONNX 格式的模型

从文件列表还可以看到部分使用 ONNX:

./TabCls/paddle_table_cls/PP-LCNet_x1_0_table_cls.onnx
./OriCls/paddle_orientation_classification/PP-LCNet_x1_0_doc_ori.onnx
./TabRec/UnetStructure/unet.onnx
./TabRec/SlanetPlus/slanet-plus.onnx

这些使用 ONNX Runtime 推理:

# mineru/model/table/rec/slanet_plus/main.py
class RapidTableModel:
    def __init__(self, model_path):
        import onnxruntime as ort
        self.session = ort.InferenceSession(
            model_path,
            providers=['CUDAExecutionProvider', 'CPUExecutionProvider']
        )

7. 转换工具

MinerU 团队使用的转换工具可能包括:

  1. Paddle2ONNX - 官方转换工具

    paddle2onnx --model_dir paddle_model \
               --model_filename model.pdmodel \
               --params_filename model.pdiparams \
               --save_file model.onnx
    
  2. X2Paddle - Paddle 到其他框架的转换

    x2paddle --framework=paddle \
            --model=model.pdmodel \
            --params=model.pdiparams \
            --save_dir=pytorch_model \
            --to_framework=pytorch
    
  3. 自定义转换脚本 - 直接映射权重

    import paddle
    import torch
       
    # 加载 Paddle 模型
    paddle_state_dict = paddle.load('model.pdparams')
       
    # 转换为 PyTorch 格式
    torch_state_dict = convert_paddle_to_torch(paddle_state_dict)
       
    # 保存为 .pth
    torch.save(torch_state_dict, 'model.pth')
    

总结

MinerU 中 PaddleOCR 模型的实际情况

特性 说明
原始格式 PaddlePaddle (.pdparams + .pdmodel)
转换后格式 PyTorch (.pth) 或 ONNX (.onnx)
推理引擎 PyTorch / ONNX Runtime
是否转换 已转换,不是原生 Paddle 格式
优势 统一推理引擎,无需安装 PaddlePaddle

为什么要转换

  1. 依赖简化:无需安装 PaddlePaddle 框架
  2. 性能优化:PyTorch/ONNX 推理可能更快
  3. 部署方便:PyTorch 生态更成熟
  4. 统一架构:其他模型都是 PyTorch,统一管理

所以答案是:MinerU 使用的是已经转换为 PyTorch (.pth) 或 ONNX (.onnx) 格式的 PaddleOCR 模型,不是原生 Paddle 格式