将 PyTorch 与 Celery 结合使用
Using PyTorch with Celery
我正在尝试 运行 Django 应用程序中的 PyTorch 模型。由于不建议在视图中执行模型(或任何 long-运行ning 任务),我决定在 Celery 任务中 运行 它。我的模型很大,加载大约需要 12 秒,推断大约需要 3 秒。这就是为什么我决定不能在每次请求时都加载它。所以我试着在设置中加载它并将它保存在那里供应用程序使用它。所以我最终的方案是:
- 当 Django 应用程序启动时,在设置中加载 PyTorch 模型并且可以从该应用程序访问它。
- 当views.py收到一个请求,它会延迟一个celery任务
- celery 任务使用 settings.model 来推断结果
这里的问题是celery任务在尝试使用模型时抛出如下错误
[2020-08-29 09:03:04,015: ERROR/ForkPoolWorker-1] Task app.tasks.task[458934d4-ea03-4bc9-8dcd-77e4c3a9caec] raised unexpected: RuntimeError("Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you must use the 'spawn' start method")
Traceback (most recent call last):
File "/home/ubuntu/anaconda3/envs/tensor/lib/python3.7/site-packages/celery/app/trace.py", line 412, in trace_task
R = retval = fun(*args, **kwargs)
File "/home/ubuntu/anaconda3/envs/tensor/lib/python3.7/site-packages/celery/app/trace.py", line 704, in __protected_call__
return self.run(*args, **kwargs)
/*...*/
File "/home/ubuntu/anaconda3/envs/tensor/lib/python3.7/site-packages/torch/cuda/__init__.py", line 191, in _lazy_init
"Cannot re-initialize CUDA in forked subprocess. " + msg)
RuntimeError: Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you must use the 'spawn' start method
这是我 settings.py 加载模型时的代码:
if sys.argv and sys.argv[0].endswith('celery') and 'worker' in sys.argv: #In order to load only for the celery worker
import torch
torch.cuda.init()
torch.backends.cudnn.benchmark = True
load_model_file()
以及任务代码
@task
def getResult(name):
print("Executing on GPU:", torch.cuda.is_available())
if os.path.isfile(name):
try:
outpath = model_inference(name)
os.remove(name)
return outpath
except OSError as e:
print("Error", name, "doesn't exist")
return ""
任务中的打印显示"Executing on GPU: true"
我尝试在 torch.cuda.init()
之前和之后的 settings.py 中设置 torch.multiprocessing.set_start_method('spawn')
,但它给出了相同的错误。
只要您还使用同一库中的 Process
,设置此方法就有效。
from torch.multiprocessing import Pool, Process
Celery 使用“常规”multiprocessing
库,因此出现此错误。
如果我是你,我会尝试:
- run it single threaded 看看是否有帮助
- run it with eventlet 看看是否有帮助
- read this
这是因为 Celery worker 本身正在使用分叉。这似乎是当前 known issue 的 Celery >=4.0
您过去可以将 celery 配置为 spawn 而不是 fork,但该功能 (CELERYD_FORCE_EXECV
) 是 removed in 4.0。
没有内置选项可以解决这个问题。一些自定义的 monkeypatching 来做到这一点可能是可能的,但是 YMMV
一些可能可行的选择可能是:
- 在启用
CELERYD_FORCE_EXECV
的情况下使用芹菜 <4.0
。
- 在 Windows 上启动 celery worker(无论如何都不可能进行分叉)
快速解决方法是制作东西 single-threaded。为此,在启动 celery worker
时将 celery 的工作池类型设置为 solo
celery -A your_proj worker -P solo -l info
我正在尝试 运行 Django 应用程序中的 PyTorch 模型。由于不建议在视图中执行模型(或任何 long-运行ning 任务),我决定在 Celery 任务中 运行 它。我的模型很大,加载大约需要 12 秒,推断大约需要 3 秒。这就是为什么我决定不能在每次请求时都加载它。所以我试着在设置中加载它并将它保存在那里供应用程序使用它。所以我最终的方案是:
- 当 Django 应用程序启动时,在设置中加载 PyTorch 模型并且可以从该应用程序访问它。
- 当views.py收到一个请求,它会延迟一个celery任务
- celery 任务使用 settings.model 来推断结果
这里的问题是celery任务在尝试使用模型时抛出如下错误
[2020-08-29 09:03:04,015: ERROR/ForkPoolWorker-1] Task app.tasks.task[458934d4-ea03-4bc9-8dcd-77e4c3a9caec] raised unexpected: RuntimeError("Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you must use the 'spawn' start method")
Traceback (most recent call last):
File "/home/ubuntu/anaconda3/envs/tensor/lib/python3.7/site-packages/celery/app/trace.py", line 412, in trace_task
R = retval = fun(*args, **kwargs)
File "/home/ubuntu/anaconda3/envs/tensor/lib/python3.7/site-packages/celery/app/trace.py", line 704, in __protected_call__
return self.run(*args, **kwargs)
/*...*/
File "/home/ubuntu/anaconda3/envs/tensor/lib/python3.7/site-packages/torch/cuda/__init__.py", line 191, in _lazy_init
"Cannot re-initialize CUDA in forked subprocess. " + msg)
RuntimeError: Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you must use the 'spawn' start method
这是我 settings.py 加载模型时的代码:
if sys.argv and sys.argv[0].endswith('celery') and 'worker' in sys.argv: #In order to load only for the celery worker
import torch
torch.cuda.init()
torch.backends.cudnn.benchmark = True
load_model_file()
以及任务代码
@task
def getResult(name):
print("Executing on GPU:", torch.cuda.is_available())
if os.path.isfile(name):
try:
outpath = model_inference(name)
os.remove(name)
return outpath
except OSError as e:
print("Error", name, "doesn't exist")
return ""
任务中的打印显示"Executing on GPU: true"
我尝试在 torch.cuda.init()
之前和之后的 settings.py 中设置 torch.multiprocessing.set_start_method('spawn')
,但它给出了相同的错误。
只要您还使用同一库中的 Process
,设置此方法就有效。
from torch.multiprocessing import Pool, Process
Celery 使用“常规”multiprocessing
库,因此出现此错误。
如果我是你,我会尝试:
- run it single threaded 看看是否有帮助
- run it with eventlet 看看是否有帮助
- read this
这是因为 Celery worker 本身正在使用分叉。这似乎是当前 known issue 的 Celery >=4.0
您过去可以将 celery 配置为 spawn 而不是 fork,但该功能 (CELERYD_FORCE_EXECV
) 是 removed in 4.0。
没有内置选项可以解决这个问题。一些自定义的 monkeypatching 来做到这一点可能是可能的,但是 YMMV
一些可能可行的选择可能是:
- 在启用
CELERYD_FORCE_EXECV
的情况下使用芹菜<4.0
。 - 在 Windows 上启动 celery worker(无论如何都不可能进行分叉)
快速解决方法是制作东西 single-threaded。为此,在启动 celery worker
时将 celery 的工作池类型设置为 solocelery -A your_proj worker -P solo -l info