Caffe2:加载ONNX模型,并在多核主机上进行单线程推理 / docker
Caffe2: Load ONNX model, and inference single threaded on multi-core host / docker
当主机有多个内核时,我在 运行 对 docker 中的模型进行推理时遇到问题。该模型通过 PyTorch 1.0 ONNX 导出器导出:
torch.onnx.export(pytorch_net, dummyseq, ONNX_MODEL_PATH)
使用单核启动模型服务器(包装在 Flask 中)产生可接受的性能(cpuset 将进程固定到特定的 cpus)docker run --rm -p 8081:8080 --cpus 0.5 --cpuset-cpus 0 my_container
来自 ab -c 1 -n 1000 http://0.0.0.0:8081/predict\?itemids\=5,100
的回复
Percentage of the requests served within a certain time (ms)
50% 5
66% 5
75% 5
80% 5
90% 7
95% 46
98% 48
99% 49
但是将它固定到四个内核会为相同的 ab-call 提供完全不同的统计数据 docker run --rm -p 8081:8080 --cpus 0.5 --cpuset-cpus 0,1,2,3 my_container
Percentage of the requests served within a certain time (ms)
50% 9
66% 12
75% 14
80% 18
90% 62
95% 66
98% 69
99% 69
100% 77 (longest request)
模型推理是这样完成的,除了这个问题,它似乎按预期工作。 (当然,这个 运行s 在与模型导出完全不同的环境中)
from caffe2.python import workspace
from caffe2.python.onnx.backend import Caffe2Backend as c2
from onnx import ModelProto
class Model:
def __init__(self):
self.predictor = create_caffe2_predictor(path)
@staticmethod
def create_caffe2_predictor(onnx_file_path):
with open(onnx_file_path, 'rb') as onnx_model:
onnx_model_proto = ModelProto()
onnx_model_proto.ParseFromString(onnx_model.read())
init_net, predict_net = c2.onnx_graph_to_caffe2_net(onnx_model_proto)
predictor = workspace.Predictor(init_net, predict_net)
return predictor
def predict(self, numpy_array):
return self.predictor.run({'0': numpy_array})
** wrapper flask app which calls Model.predict() on calls to /predict **
OMP_NUM_THREADS=1
也存在于容器环境中,有一些效果,但不是最终问题。
您在这里看到的基准统计数据是 运行 在具有 8 个超线程的本地计算机上,因此我不应该让我的计算机饱和并影响测试。这些结果也出现在我的 kubernetes 环境中,我在那里得到了大量的 CFS(完全公平调度程序)节流。
我 运行 在 kubernetes 环境中工作,所以我无法控制主机公开的 CPU 数量,并且在那里进行某种固定似乎也有点老套。
有什么方法可以将 caffe2 模型推断固定到单个处理器上吗?我在这里做错了什么吗? caffe2.Predictor 对象不适合这个任务吗?
感谢任何帮助。
编辑:
我在这里添加了我能想到的最简单的可重现示例,其中包含 docker-容器和 运行-脚本:https://github.com/NegatioN/Caffe2Struggles
我认为这应该可行:
workspace.GlobalInit(["caffe2", "--caffe2_omp_num_threads=1"])
这不是问题的直接答案,但如果您的目标是在生产中提供 PyTorch 模型(并且只有 PyTorch 模型,就像我现在这样),那么简单地使用 PyTorch Tracing 似乎更好选择.
然后您可以将其直接加载到 C++ 前端,类似于通过 Caffe2 执行的操作,但 PyTorch 跟踪似乎维护得更好。据我所知,速度没有下降,但配置起来要容易得多。
在单核容器上获得良好性能的一个例子是 运行 和 OMP_NUM_THREADS=1
一样,然后导出模型如下:
from torch import jit
### Create a model
model.eval()
traced = jit.trace(model, torch.from_numpy(an_array_with_input_size))
traced.save("traced.pt")
然后简单地 运行 按照上述指南在纯 C++ 中生产的模型,或者通过 Python 接口:
from torch import jit
model = jit.load("traced.pt")
output = model(some_input)
当主机有多个内核时,我在 运行 对 docker 中的模型进行推理时遇到问题。该模型通过 PyTorch 1.0 ONNX 导出器导出:
torch.onnx.export(pytorch_net, dummyseq, ONNX_MODEL_PATH)
使用单核启动模型服务器(包装在 Flask 中)产生可接受的性能(cpuset 将进程固定到特定的 cpus)docker run --rm -p 8081:8080 --cpus 0.5 --cpuset-cpus 0 my_container
来自 ab -c 1 -n 1000 http://0.0.0.0:8081/predict\?itemids\=5,100
Percentage of the requests served within a certain time (ms)
50% 5
66% 5
75% 5
80% 5
90% 7
95% 46
98% 48
99% 49
但是将它固定到四个内核会为相同的 ab-call 提供完全不同的统计数据 docker run --rm -p 8081:8080 --cpus 0.5 --cpuset-cpus 0,1,2,3 my_container
Percentage of the requests served within a certain time (ms)
50% 9
66% 12
75% 14
80% 18
90% 62
95% 66
98% 69
99% 69
100% 77 (longest request)
模型推理是这样完成的,除了这个问题,它似乎按预期工作。 (当然,这个 运行s 在与模型导出完全不同的环境中)
from caffe2.python import workspace
from caffe2.python.onnx.backend import Caffe2Backend as c2
from onnx import ModelProto
class Model:
def __init__(self):
self.predictor = create_caffe2_predictor(path)
@staticmethod
def create_caffe2_predictor(onnx_file_path):
with open(onnx_file_path, 'rb') as onnx_model:
onnx_model_proto = ModelProto()
onnx_model_proto.ParseFromString(onnx_model.read())
init_net, predict_net = c2.onnx_graph_to_caffe2_net(onnx_model_proto)
predictor = workspace.Predictor(init_net, predict_net)
return predictor
def predict(self, numpy_array):
return self.predictor.run({'0': numpy_array})
** wrapper flask app which calls Model.predict() on calls to /predict **
OMP_NUM_THREADS=1
也存在于容器环境中,有一些效果,但不是最终问题。
您在这里看到的基准统计数据是 运行 在具有 8 个超线程的本地计算机上,因此我不应该让我的计算机饱和并影响测试。这些结果也出现在我的 kubernetes 环境中,我在那里得到了大量的 CFS(完全公平调度程序)节流。
我 运行 在 kubernetes 环境中工作,所以我无法控制主机公开的 CPU 数量,并且在那里进行某种固定似乎也有点老套。
有什么方法可以将 caffe2 模型推断固定到单个处理器上吗?我在这里做错了什么吗? caffe2.Predictor 对象不适合这个任务吗?
感谢任何帮助。
编辑:
我在这里添加了我能想到的最简单的可重现示例,其中包含 docker-容器和 运行-脚本:https://github.com/NegatioN/Caffe2Struggles
我认为这应该可行:
workspace.GlobalInit(["caffe2", "--caffe2_omp_num_threads=1"])
这不是问题的直接答案,但如果您的目标是在生产中提供 PyTorch 模型(并且只有 PyTorch 模型,就像我现在这样),那么简单地使用 PyTorch Tracing 似乎更好选择.
然后您可以将其直接加载到 C++ 前端,类似于通过 Caffe2 执行的操作,但 PyTorch 跟踪似乎维护得更好。据我所知,速度没有下降,但配置起来要容易得多。
在单核容器上获得良好性能的一个例子是 运行 和 OMP_NUM_THREADS=1
一样,然后导出模型如下:
from torch import jit
### Create a model
model.eval()
traced = jit.trace(model, torch.from_numpy(an_array_with_input_size))
traced.save("traced.pt")
然后简单地 运行 按照上述指南在纯 C++ 中生产的模型,或者通过 Python 接口:
from torch import jit
model = jit.load("traced.pt")
output = model(some_input)