Paddle python API放到multiprocess_reader中预测报cuda错

vohkndzv  于 2021-11-30  发布在  Java
关注(0)|答案(27)|浏览(474)

我的需求是在reader中使用inference_model进行预测,reader放在multiprocess_reader中。使用了两种实现方式都报错:Error: cudaSetDevice failed in paddle::platform::SetDeviced, error code : 3, Please see detail in https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__TYPES.htm l#group__CUDART__TYPES_1g3f51e3575c2178246db0a94a430e0038: initialization error at (/paddle/paddle/fluid/platform/gpu_info.cc:240)
第一种是:在reader中定义CUDAPlace和exe;第二种是在reader中使用python API预测。其中第二种方法在pool构造的多进程中没问题,在本场景的multiprocess_reader中有问题。
最小可复现代码:paddle1.7 post97

import os
os.environ["CUDA_VISIBLE_DEVICES"]="2"
import paddle
import paddle.fluid as fluid
from paddle.fluid.core import PaddleTensor
from paddle.fluid.core import AnalysisConfig
from paddle.fluid.core import create_paddle_predictor
def reader():
    landmark_config = AnalysisConfig('lmk_model/model','lmk_model/params')
    landmark_config.switch_use_feed_fetch_ops(False)
    #landmark_config.disable_gpu() 
    landmark_config.enable_use_gpu(100, 0)  
    landmark_predictor = create_paddle_predictor(landmark_config) 
    for i in range(10):
        yield i
if __name__=="__main__":
    place = fluid.CUDAPlace(0)
    exe = fluid.Executor(place)
    train_reader = paddle.reader.multiprocess_reader([reader, reader])
    for data in train_reader():
        print(data)
lp0sw83n

lp0sw83n1#

什么原因呢?而且我的场景里就是需要在multiprocess_reader里的reader里进行预测,得把这个方案走通

pbgvytdp

pbgvytdp2#

好吧,我没想到这个问题这么复杂。我试试paddle server方法吧。

gev0vcfq

gev0vcfq3#

嗯嗯,所以结论是目前想在主进程中创建子进程,在子进程中做inference这种思路在目前的paddle实现下是行不通的,这也不是一个bug修复的问题,而是架构层面的设计就不满足这样的写法,所以对于您这个需求,需要想别的办法,您看看reader多线程用GPU做inference能满足需求吗?

zi8p0yeb

zi8p0yeb4#

这种方法也不行,我的主进程里需要进行训练啊

hfwmuf9z

hfwmuf9z5#

@wang-kangkang import paddle的时候会在当前进程初始化cuda的环境,如果一定要用子进程的话,只能在子进程中import paddle了,这样倒不会报错,但应该也没法用了吧。。。

import os
import numpy as np
import multiprocessing

os.environ["CUDA_VISIBLE_DEVICES"]="0"

def _read_into_queue(reader, queue):
    try:
        for sample in reader():
            if sample is None:
                raise ValueError("sample has None")
            queue.put(sample)
        queue.put(None)
    except:
        queue.put("")
        six.reraise(*sys.exc_info())

def queue_reader(readers):
    queue = multiprocessing.Queue(10)
    for reader in readers:
        p = multiprocessing.Process(
            target=_read_into_queue, args=(reader, queue))
        p.start()

    reader_num = len(readers)
    finish_num = 0
    while finish_num < reader_num:
        sample = queue.get()
        if sample is None:
            finish_num += 1
        elif sample == "":
            raise ValueError("multiprocess reader raises an exception")
        else:
            yield sample

def reader():
    def __impl__():
      import paddle
      import paddle.fluid as fluid

      place = fluid.CUDAPlace(0)
      exe = fluid.Executor(place)

      [inference_program, feed_target_names, fetch_targets] = (
          fluid.io.load_inference_model(dirname="./save_load/fc.example.model", executor=exe))

      tensor_img = np.array(np.random.random((1, 784)), dtype=np.float32)
      results = exe.run(inference_program,
                        feed={feed_target_names[0]: tensor_img},
                        fetch_list=fetch_targets)
      yield results[0]

    return __impl__

if __name__=="__main__":
    train_reader = queue_reader([reader()])
    for data in train_reader:
        print(data)
ui7jx7zq

ui7jx7zq6#

reader是否可以用多线程

mkshixfv

mkshixfv7#

reader中使用place=fluid.CPUPlace()速度同样很慢,我期望的是起码能实用python API能在reader中调用cuda预测。

agxfikkp

agxfikkp8#

那在reader中去掉cuda相关(或者接口内部有调用cuda)的代码吧

xmjla07d

xmjla07d9#

使用多线程会降低原有的训练速度。所以有没有办法能直面并解决当前问题

vd8tlhqk

vd8tlhqk10#

这个错误,具体的原因是,CUDA的context不能在多进程内共享。

If you create a CUDA context before the fork(), 
you cannot use that within the child process. 
The cudaSetDevice(0); call attempts to share the CUDA context,
implicitly created in the parent process when you call cudaGetDeviceCount();

具体的解释可见:
https://stackoverflow.com/questions/22950047/cuda-initialization-error-after-fork

在调用 paddle.reader.multiprocess_reader 之后会fork出子进程,但是在这之前paddle会初始化cuda context,因此会有上述的问题。

Paddle/python/paddle/fluid/init.py

Line 221 in cb0472b

| | core.init_devices(notin_test) |

Paddle/paddle/fluid/pybind/pybind.cc

Line 1533 in cb0472b

| | m.def("init_devices", |

https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/fluid/platform/init.cc#L139-L154

因此在使用cuda期间避免fork多进程,建议使用多线程。

knpiaxh1

knpiaxh111#

需求场景是我在训练人脸检测模型的时候,想要在检测模型上再出另一个分支来输出人脸的模糊属性。由于检测的数据产生过程有data argument,其中会改变人脸模糊度和大小,所以模糊属性无法提前离线标注。当前的方法就是使用一个提前训练好的模糊分类小模型,在reader中的data argument之后进行inference,从而获得模糊度“标签”。
目前在reader中使用cpu预测十分慢,整体训练速度不到原先的40%

yruzcnhs

yruzcnhs12#

@wang-kangkang 这里应该是因为,从框架层面来讲的话,import paddle的时候,会初始化的CUDADeviceContext,而一旦初始化之后,就不能共享给主进程创建的子进程使用,而要支持这种写法,涉及到的底层改动还是挺大的,后续反馈下要不要做,一时半会这种写法应该不行,单预测API的话等等 @NHZIX 回复

为什么一定要这么写?这个本质需求是预测的速度不够快吗?

byqmnocz

byqmnocz13#

@wang-kangkang 我这边试了下,把exe塞到子进程里执行就会报这个错,还需要时间分析下
@NHZlX 说预测python API理论上支持这种第二种写法,麻烦等他回复下

liwlm1x9

liwlm1x914#

稍等,我再排查一下

6vl6ewon

6vl6ewon15#

在这个例子中,不用multiprocess_reader装饰是可以正常工作的吗

相关问题