tritonserver学习之五:backend实现机制

发布时间:2024年01月25日

tritonserver学习之一:triton使用流程

tritonserver学习之二:tritonserver编译

tritonserver学习之三:tritonserver运行流程

tritonserver学习之四:命令行解析

1、预备知识

1.1 backend概念

? ? ?backend是triton中的核心部件,它负责处理来自客户端的推理请求,并将请求转发给相应的模型进行推理。每个backend都对应一个特定的深度学习框架,例如TensorFlow、PyTorch、ONNX、paddle等。当客户端发送推理请求时,Triton Server会根据请求的模型和版本信息,将请求路由到相应的backend进行处理。

1.2 模型配置

? ? ?大家知道,triton serve的每个模型都有个配置文件:config.pbtxt,这个配置中,明确了模型的meta信息,当然也包含了对应backend信息,例如代码中的官方模型simple的配置如下:

name: "simple"
platform: "tensorflow_graphdef"
max_batch_size: 8
input [
  {
    name: "INPUT0"
    data_type: TYPE_INT32
    dims: [ 16 ]
  },
  {
    name: "INPUT1"
    data_type: TYPE_INT32
    dims: [ 16 ]
  }
]
output [
  {
    name: "OUTPUT0"
    data_type: TYPE_INT32
    dims: [ 16 ]
  },
  {
    name: "OUTPUT1"
    data_type: TYPE_INT32
    dims: [ 16 ]
  }
]

看到这个配置可能会有疑惑,配置中没有设置banckend的信息,哪triton是如何找到对应的backend的呢,答案是通过【platform】这个字段找到的,为什么是通过这个字段找到的,先不细讲,大概说一下,先看如下代码,位于core代码库,位于core/src/constants.h:

constexpr char kTensorFlowGraphDefPlatform[] = "tensorflow_graphdef";
constexpr char kTensorFlowSavedModelPlatform[] = "tensorflow_savedmodel";
constexpr char kTensorFlowGraphDefFilename[] = "model.graphdef";
constexpr char kTensorFlowSavedModelFilename[] = "model.savedmodel";
constexpr char kTensorFlowBackend[] = "tensorflow";

【platform】这个字段的设置是要求的,对于TensorFlow模型,云端推理上线主要有两种格式,分别为:

GraphDef
SavedModel(推荐)

对应的【platform】字段是固定的,分别为:tensorflow_graphdef和tensorflow_savedmodel,triton就是通过这两个字符串来找到对应的backend的。

1.3 backend实现简介

triton所有backend的实现,包括pytorch_backend、paddle_backend等所有backend的实现,实现原理都是一样的,大家可以看一下源码,主要是实现7个api:

TRITONBACKEND_Initialize:创建ModelState对象。
TRITONBACKEND_ModelInitialize
TRITONBACKEND_ModelInstanceInitialize:创建ModelInstanceState对象,可以通过这个对象调用LoadModel函数
TRITONBACKEND_ModelInstanceExecute
TRITONBACKEND_ModelInstanceFinalize
TRITONBACKEND_ModelFinalize
TRITONBACKEND_Finalize

架构如下:

1.4 dlopen系列函数

?linux系统提供一套api,实现了动态加载so,triton中,对各个backend库的加载使用的就是这种方式,api的原型如下:

void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);

使用上面函数之前,需要包含头文件:

#include <dlfcn.h>

dlopen:以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。

dlsym:在打开的动态库中查找符号的值,其不仅能够获取函数地址,也能够获取全局变量地址,非常之方便。

dlclose:关闭动态库。

dlerror:返回一个描述最后一次调用dlopen、dlsym,或dlclose的错误信息的字符串。

2、backend实现

tirton中,对banckend的管理,主要在core代码中,代码位于:core/src/backend_manager.cc中,主要是两个类:

class TritonBackendManager {}
class TritonBackend {}

这两个类,严格来说,只是banckend的一个proxy,这两个类最重要的就是获取到模型对应backend的7个api,获取api指针后,用于之后的推理。

2.1?TritonBackendManager类说明

TritonBackendManager类的定义如下:

class TritonBackendManager {
 public:
  static Status Create(std::shared_ptr<TritonBackendManager>* manager);

  Status CreateBackend(
      const std::string& name, const std::string& dir,
      const std::string& libpath,
      const triton::common::BackendCmdlineConfig& backend_cmdline_config,
      bool is_python_based_backend, std::shared_ptr<TritonBackend>* backend);

  Status BackendState(
      std::unique_ptr<
          std::unordered_map<std::string, std::vector<std::string>>>*
          backend_state);

 private:
  DISALLOW_COPY_AND_ASSIGN(TritonBackendManager);
  TritonBackendManager() = default;
  std::unordered_map<std::string, std::shared_ptr<TritonBackend>> backend_map_;
};

Create:这个函数比较好理解,静态函数,创建?TritonBackendManager类对象。

CreateBackend:根据backend名称、so路径、配置,创建对应的backend,如果TRITONBACKEND_Initialize函数指针不为空,则运行该函数。

BackendState获取backend配置信息,例如:

2.2?class TritonBackend类

这个类直接和各个backend进行交互,加载backend动态库,同时获取对应的7个api函数指针。

class TritonBackend {
 public:
  struct Attribute {
    Attribute()
        : exec_policy_(TRITONBACKEND_EXECUTION_BLOCKING),
          parallel_instance_loading_(false)
    {
    }
    TRITONBACKEND_ExecutionPolicy exec_policy_;
    std::vector<inference::ModelInstanceGroup> preferred_groups_;
    // Whether the backend supports loading model instances in parallel
    bool parallel_instance_loading_;
  };
  typedef TRITONSERVER_Error* (*TritonModelInitFn_t)(
      TRITONBACKEND_Model* model);
  typedef TRITONSERVER_Error* (*TritonModelFiniFn_t)(
      TRITONBACKEND_Model* model);
  typedef TRITONSERVER_Error* (*TritonModelInstanceInitFn_t)(
      TRITONBACKEND_ModelInstance* instance);
  typedef TRITONSERVER_Error* (*TritonModelInstanceFiniFn_t)(
      TRITONBACKEND_ModelInstance* instance);
  typedef TRITONSERVER_Error* (*TritonModelInstanceExecFn_t)(
      TRITONBACKEND_ModelInstance* instance, TRITONBACKEND_Request** requests,
      const uint32_t request_cnt);

  static Status Create(
      const std::string& name, const std::string& dir,
      const std::string& libpath,
      const triton::common::BackendCmdlineConfig& backend_cmdline_config,
      std::shared_ptr<TritonBackend>* backend);
  ~TritonBackend();

  const std::string& Name() const { return name_; }
  const std::string& Directory() const { return dir_; }
  const std::string& LibPath() const { return libpath_; }
  const TritonServerMessage& BackendConfig() const { return backend_config_; }
  const Attribute& BackendAttributes() const { return attributes_; }

  TRITONBACKEND_ExecutionPolicy ExecutionPolicy() const
  {
    return attributes_.exec_policy_;
  }
  void SetExecutionPolicy(const TRITONBACKEND_ExecutionPolicy policy)
  {
    attributes_.exec_policy_ = policy;
  }

  void* State() { return state_; }
  void SetState(void* state) { state_ = state; }
  bool IsPythonBackendBased() { return is_python_based_backend_; }
  void SetPythonBasedBackendFlag(bool is_python_based_backend)
  {
    is_python_based_backend_ = is_python_based_backend;
  }

  TritonModelInitFn_t ModelInitFn() const { return model_init_fn_; }
  TritonModelFiniFn_t ModelFiniFn() const { return model_fini_fn_; }
  TritonModelInstanceInitFn_t ModelInstanceInitFn() const
  {
    return inst_init_fn_;
  }
  TritonModelInstanceFiniFn_t ModelInstanceFiniFn() const
  {
    return inst_fini_fn_;
  }
  TritonModelInstanceExecFn_t ModelInstanceExecFn() const
  {
    return inst_exec_fn_;
  }

 private:
  typedef TRITONSERVER_Error* (*TritonBackendInitFn_t)(
      TRITONBACKEND_Backend* backend);
  typedef TRITONSERVER_Error* (*TritonBackendFiniFn_t)(
      TRITONBACKEND_Backend* backend);
  typedef TRITONSERVER_Error* (*TritonBackendAttriFn_t)(
      TRITONBACKEND_Backend* backend,
      TRITONBACKEND_BackendAttribute* backend_attributes);

  TritonBackend(
      const std::string& name, const std::string& dir,
      const std::string& libpath, const TritonServerMessage& backend_config);

  void ClearHandles();
  Status LoadBackendLibrary();

  Status UpdateAttributes();

  // The name of the backend.
  const std::string name_;

  // Full path to the directory holding backend shared library and
  // other artifacts.
  const std::string dir_;

  // Full path to the backend shared library.
  const std::string libpath_;

  bool is_python_based_backend_;

  // Backend configuration as JSON
  TritonServerMessage backend_config_;

  // backend attributes
  Attribute attributes_;

  // dlopen / dlsym handles
  void* dlhandle_;
  TritonBackendInitFn_t backend_init_fn_;
  TritonBackendFiniFn_t backend_fini_fn_;
  TritonBackendAttriFn_t backend_attri_fn_;
  TritonModelInitFn_t model_init_fn_;
  TritonModelFiniFn_t model_fini_fn_;
  TritonModelInstanceInitFn_t inst_init_fn_;
  TritonModelInstanceFiniFn_t inst_fini_fn_;
  TritonModelInstanceExecFn_t inst_exec_fn_;

  // Opaque state associated with the backend.
  void* state_;
}

create函数:静态函数,创建该类的对象。

其他函数基本都是围绕加载so,获取api函数指针相关。

以上就是backend相关的知识。

3、总结

? ? ? triton支持了目前市场上所有主流的深度学习框架,对于paddle,官方镜像只有21.10版本支持,其他版本都不支持,如果需要在新版本支持,则需要自己进行编译,可以参考前面编写的博客,编译部分:tritonserver学习之二:tritonserver编译-CSDN博客,博客中介绍的backend的类,主要还是一个proxy的作用,直接调用深度学习api的还是对应的backend,大家可以自己学习理解下,不清楚的,欢迎评论交流。欢迎各位同行关注一下公众号:

文章来源:https://blog.csdn.net/liupenglove/article/details/135710496
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。