1 PaddleOCR-VL在GPU上随机出现推理假死问题

之前在一个自己的一个算法管线里面加入了PaddleOCR-VL用于文字识别,我的数据是一连串的图片。

今天突然发现提交的一个任务在PaddleOCR-VL模型调用predict方法推理的时候会卡在那里,既没有爆显存,python也没有捕捉到任何异常和报错信息,它就是单纯的卡在那里,导致整个算法pipeline假死,无法处理新的任务。但是我重新启动算法之后,它又可以推理了,然后又会在某个任务又假死在那里,如此循环往复。

无奈之下上了日志大法,在PaddleOCR-VL推理前和推理后都加上日志:

logger.info(f"paddleocr_vl predict before")
out = self.paddleocr_vl.predict(
        input=input_roi,
        use_doc_orientation_classify=False,
        use_doc_unwarping=False,
        use_layout_detection=False,
        use_chart_recognition=False,
        prompt_label="ocr",
    )
logger.info(f"paddleocr_vl predict after")

在假死的情况下,只会打印“paddleocr_vl predict before”这一句日志,之后推理流程像蒸发一样,就好像从来没有这个推理任务,关键是没有任何报错信息和超时,模型还占着显存,但是显卡利用率为0。

2 问题排查

无奈之下,去paddlepaddle官方仓库看有没有大聪明和我一样遇到了这个问题,发现世界上的大聪明不只我一个,贴下issue链接:

  1. https://github.com/PaddlePaddle/PaddleOCR/issues/17693
  2. https://github.com/PaddlePaddle/PaddleOCR/issues/17640

有佬用strace对卡住的python进程进行跟踪,发现存在同一个ioctl调用的死循环:

ioctl(9, _IOC(_IOC_READ|_IOC_WRITE, 0x46, 0x2a, 0x20), 0x7ffd08752fa0) = 0
ioctl(9, _IOC(_IOC_READ|_IOC_WRITE, 0x46, 0x2a, 0x20), 0x7ffd08752fa0) = 0
ioctl(9, _IOC(_IOC_READ|_IOC_WRITE, 0x46, 0x2a, 0x20), 0x7ffd08752fa0) = 0
... (repeats forever)

这个ioctl对应NVIDIA的NV_ESC_RM_CONTROL,是PaddlePaddle显存分配器陷入死循环,一直在尝试分配GPU显存,但是一直没成功。

我也用strace查了一下,确实找到了这个输出,这里要感谢下巨佬,原因找到了!

3 解决方法

在python中导入PaddlePaddle之前设置环境变量:

import os
os.environ["FLAGS_allocator_strategy"] = "naive_best_fit"

或者直接设置环境变量

export FLAGS_allocator_strategy=naive_best_fit

这样PaddlePaddle会使用naive_best_fit显存分配器。这里FLAGS_allocator_strategy有两个选项:

  • auto_growth:默认方式,按需分配GPU显存,但可能产生显存碎片
  • naive_best_fit:预先分配GPU显存

通过上述方式设置

FLAGS_allocator_strategy=naive_best_fit

之后,在加载模型时会预先分配GPU显存,而不是按需申请显存,所以就不会进入到ioctl显存申请死循环。

参考链接

  1. https://github.com/PaddlePaddle/PaddleOCR/issues/17693
  2. https://github.com/PaddlePaddle/PaddleOCR/issues/17640
  3. https://docs.alauda.io/container_platform/4.0/hardware_accelerator/application_development/trouble_shooting/paddle_native_best.html