Skip to content

Latest commit

 

History

History
227 lines (168 loc) · 5.5 KB

MEMORY_FIX.md

File metadata and controls

227 lines (168 loc) · 5.5 KB

Marker-PDF 显存管理改进方案

问题根源

为什么间歇性OOM:

  1. 临时对象未清理:每个PDF转换产生大量临时对象(rendered、text、images),这些对象占用GPU内存但没有立即释放
  2. 清理不同步:torch.cuda.empty_cache()是异步的,不保证立即生效
  3. 累积效应:简单PDF显存占用小,复杂PDF占用大,累积后突然OOM

已实施的改进

1. 每个文件强制清理

def convert_file(self, pdf_path: str) -> tuple[str, dict]:
    # 转换
    rendered = self.converter(pdf_path)
    text, _, images = text_from_rendered(rendered)
    
    # 立即删除临时对象
    del rendered
    del text
    del images
    
    # 强制垃圾回收
    import gc
    gc.collect()
    
    # 清空CUDA缓存
    torch.cuda.empty_cache()
    torch.cuda.synchronize()  # 关键:强制同步,确保清理完成
    
    return result_text, result_images

关键改进点:

  • 每个文件都清理,不再是每3个文件
  • 删除临时变量:rendered、text、images立即删除
  • 强制同步:torch.cuda.synchronize()确保清理立即生效,不是异步等待

2. 自动CPU降级

# 在api.py中
if "CUDA OOM" in error_msg:
    print("[Batch] Attempting fallback to CPU...")
    r = convert_file(..., device="cpu", use_cache=False)

优点:

  • GPU失败自动切CPU
  • 保持公式识别和图片裁切
  • 用户无需干预

3. 定期深度清理

# 每5个文件
if i % 5 == 0:
    torch.cuda.empty_cache()
    torch.cuda.synchronize()

# 每10个文件
if i % 10 == 0:
    gc.collect()
    clear_converter_cache()

显存占用分析

marker-pdf模型显存占用:

  • Layout模型:~1GB(检测版面、图片、表格、公式区域)
  • OCR模型:~1.5GB(识别文字和公式)
  • Table模型:~0.5GB(表格结构识别)

临时显存占用(每个文件):

  • 简单PDF(10页纯文本):~0.5GB
  • 复杂PDF(50页含图片公式):~2GB
  • 超大PDF(100+页):~4GB+

推荐使用策略

策略1:GPU自动降级(推荐)

nuoyi ./papers --batch --device cuda --existing-files update
  • 简单PDF用GPU快速处理
  • 复杂PDF自动切CPU
  • 公式和图片完美保留
  • 无需用户干预

策略2:低显存模式

nuoyi ./papers --batch --device cuda --low-vram --existing-files update
  • OCR模型放CPU,Layout模型放GPU
  • 显存占用降低到~1.5GB
  • 速度略慢(OCR在CPU)
  • 公式和图片保留

策略3:纯数字PDF优化

nuoyi ./papers --batch --device cuda --disable-ocr-models --existing-files update
  • 禁用OCR模型
  • 显存占用~1GB
  • 只适合纯数字文本PDF
  • 公式识别和图片裁切保留
  • 扫描版PDF不能用

策略4:混合策略(最稳定)

# 先用GPU快速处理简单PDF
nuoyi ./papers --batch --device cuda --low-vram --existing-files update

# 失败的再单独处理
nuoyi ./failed --batch --device cpu

公式识别和图片裁切保证

marker-pdf核心优势(不能放弃):

  1. 公式识别:

    • 自动检测公式区域
    • 提取LaTeX代码
    • 转换为可渲染的Markdown公式
    • pymupdf做不到
  2. 图片智能裁切:

    • 检测图片边界
    • 裁剪空白边缘
    • 优化分辨率
    • pymupdf只能简单提取
  3. OCR:

    • 扫描版PDF识别
    • 手写文字识别
    • pymupdf无OCR

结论:必须用marker-pdf,不能换pymupdf。

显存监控

# 实时监控GPU显存
watch -n 1 nvidia-smi

# 或者
nvidia-smi -l 1

监控指标:

  • Memory-Usage:已用显存
  • FB Memory Usage:帧缓存使用
  • GPU-Util:GPU利用率

批处理最佳实践

44315个PDF推荐流程:

  1. 分批处理:每批5000个文件,避免长时间运行累积问题
  2. 保存进度:--existing-files update 避免重复处理
  3. 监控显存:nvidia-smi -l 1 实时监控
  4. 定期重启:每批处理完重启清理所有内存
# 批处理脚本
for i in {1..9}; do
    nuoyi ./batch_$i --batch --device cuda --existing-files update
    sleep 10  # 给GPU喘息时间
done

性能对比

方案 公式识别 图片裁切 速度 显存 稳定性
GPU自动降级 ✓ 完美 ✓ 完美 快 3-4GB ★★★★★
低VRAM模式 ✓ 完美 ✓ 完美 中 1.5GB ★★★★☆
disable-ocr ✓ 完美 ✓ 完美 快 1GB ★★★★☆
纯CPU ✓ 完美 ✓ 完美 慢10倍 0GB ★★★★★
pymupdf ✗ 无 △ 简单 极快 0GB ★★★★★

改进效果预期

改进前:

  • 简单PDF + 复杂PDF混合 = 间歇性OOM
  • 显存累积,清理不及时
  • 需要手动重启或切换设备

改进后:

  • 每个文件强制清理临时显存
  • GPU同步确保清理立即生效
  • OOM自动降级CPU,无需干预
  • 稳定性大幅提升

技术细节

为什么需要synchronize():

torch.cuda.empty_cache()  # 异步,提交清理请求
torch.cuda.synchronize()  # 同步,等待清理完成
  • empty_cache()只是标记要清理,不保证立即完成
  • synchronize()强制等待GPU完成所有操作
  • 组合使用才能确保显存真正释放

为什么删除临时变量:

del rendered, text, images
  • 这些对象可能持有GPU内存引用
  • Python引用计数可能延迟释放
  • 显式删除+gc.collect()确保立即释放