【问题标题】:Caffe2: Load ONNX model, and inference single threaded on multi-core host / dockerCaffe2:加载 ONNX 模型,并在多核主机/docker 上推断单线程
【发布时间】:2019-08-04 10:38:12
【问题描述】:

当主机有多个内核时,我在 docker 中的模型上运行推理时遇到问题。模型通过 PyTorch 1.0 ONNX 导出器导出:

torch.onnx.export(pytorch_net, dummyseq, ONNX_MODEL_PATH)

使用单核启动模型服务器(封装在 Flask 中)会产生可接受的性能(cpuset 将进程固定到特定 cpu)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)

模型推理是这样完成的,除了这个问题,它似乎按预期工作。 (当然,这在与模型导出完全不同的环境中运行)

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,并且在那里进行某种固定似乎也有点 hacky。

有没有办法将 caffe2 模型推断固定到单个处理器?我在这里做明显错误的事情吗? caffe2.Predictor 对象不适合这个任务吗?

任何帮助表示赞赏。

编辑:

我在这里添加了我能想到的最简单的可重现示例,其中包括一个 docker-container 和 run-script:https://github.com/NegatioN/Caffe2Struggles

【问题讨论】:

    标签: python docker pytorch caffe2 onnx


    【解决方案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)
    

    【讨论】:

      【解决方案2】:

      我认为这应该可行:

      workspace.GlobalInit(["caffe2", "--caffe2_omp_num_threads=1"])

      【讨论】:

      • 嗨,谢尔盖。可悲的是,这并没有改变任何事情。我很确定将OMP_NUM_THREADS=1 导出到环境会得到完全相同的结果。还有其他可能的罪人需要评估吗?或者有什么简单的方法可以找到我们可以在 caffe2 上设置的那些命令行参数/ globalInit 参数的文档?感谢您的帮助
      • 您是否看到有关在日志中设置 omp_num_threads 的信息?这是相关标志和环境变量的逻辑,带有日志记录:github.com/pytorch/pytorch/blob/master/caffe2/core/init_omp.cc
      • 是的,日志至少表明 MKL 和 OMP 都有一个线程。 [V init_omp.cc:69] Caffe2 running with 1 MKL threads[V init_omp.cc:42] Caffe2 running with 1 OMP threads
      • 我添加了一个带有 docker 容器的 repo,如果您愿意查看它,希望能重现结果:github.com/NegatioN/Caffe2Struggles
      • 我认为这可能是因为 caffe2 明确将线程池大小设置为与逻辑 CPU 的数量 github.com/pytorch/pytorch/issues/18013 一样大。在这种情况下,似乎没有其他选择,只能让某人对其进行修复。
      猜你喜欢
      • 2021-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 2020-05-15
      • 1970-01-01
      相关资源
      最近更新 更多