PAI-Blade敏捷版提供了C++ SDK帮助您部署优化后的模型。本文以PyTorch模型为例,介绍PAI-Blade敏捷版SDK的使用方法。

前提条件

  • 已使用PAI-Blade敏捷版对PyTorch模型进行了优化,详情请参见优化PyTorch模型
  • 已安装SDK并获取鉴权Token,详情请参见安装PAI-Blade敏捷版。因为本文使用pre-cxx11 ABI的SDK,3.7.0版本的DEB包。
    说明 经过PAI-Blade敏捷版优化的模型,必须依赖对应的SDK才能正常运行。

准备环境

本文以CentOS 7为例,介绍如何使用PAI-Blade敏捷版SDK部署PyTorch模型。

  1. 准备服务器。
    本文使用如下配置的ECS实例:
    • 实例规格:ecs.gn6i-c4g1.xlarge,T4 GPU
    • 操作系统:Ubuntu 18.04 64位
    • 设备:CUDA 10.0
    • 显卡驱动:Driver 440.64.00
    • GPU计算加速包:CUDNN 7.6.5
  2. 安装Python 3。
    # 更新pip版本。
    python3 -m pip install --upgrade pip
    
    # 安装virtualenv,在虚拟环境中安装PyTorch。
    pip3 install virtualenv==16.0
    python3 -m virtualenv venv
    
    # 激活virtuanenv。
    source venv/bin/activate

部署模型推理

通过PAI-Blade敏捷版SDK加载并部署优化后的模型推理,您无需修改原代码逻辑,只需要在编译时链接上PAI-Blade敏捷版SDK中的库文件。

  1. 准备模型及测试数据。
    本文使用已经优化好的示例模型进行演示,通过如下命令即可下载该模型。您也可以使用自己的优化模型,关于如何使用PAI-Blade敏捷版优化模型,详情请参见优化PyTorch模型
    # 下载优化好的示例模型。
    wget http://pai-blade.oss-cn-zhangjiakou.aliyuncs.com/demo/sdk/pytorch/optimized_resnet50.pt
    # 下载对应的测试数据。
    wget http://pai-blade.oss-cn-zhangjiakou.aliyuncs.com/demo/sdk/pytorch/inputs.pth
  2. 下载并查看推理代码。
    通过PAI-Blade敏捷版优化后的模型,其执行过程与常规PyTorch模型相同,无需编写额外代码或配置额外信息。本文使用的推理代码如下所示。
    #include <torch/script.h>
    #include <torch/serialize.h>
    #include <chrono>
    #include <iostream>
    #include <fstream>
    #include <memory>
    
    int benchmark(torch::jit::script::Module &module,
                 std::vector<torch::jit::IValue> &inputs) {
      // warmup 10-iter
      for (int k = 0; k < 10; ++ k) {
        module.forward(inputs);
      }
      auto start = std::chrono::system_clock::now();
      // run 20-iter
      for (int k = 0; k < 20; ++ k) {
        module.forward(inputs);
      }
      auto end = std::chrono::system_clock::now();
      std::chrono::duration<double> elapsed_seconds = end-start;
      std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    
      std::cout << "finished computation at " << std::ctime(&end_time)
                << "\nelapsed time: " << elapsed_seconds.count() << "s"
                << "\navg latency: " << 1000.0 * elapsed_seconds.count()/20 << "ms\n";
      return 0;
    }
    
    torch::Tensor load_data(const char* data_file) {
      std::ifstream file(data_file, std::ios::binary);
      std::vector<char> data((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
      torch::IValue ivalue = torch::pickle_load(data);
      CHECK(ivalue.isTensor());
      return ivalue.toTensor();
    }
    
    int main(int argc, const char* argv[]) {
      if (argc != 3) {
        std::cerr << "usage: example-app <path-to-exported-script-module> <path-to-saved-test-data>\n";
        return -1;
      }
    
      torch::jit::script::Module module;
      try {
        // Deserialize the ScriptModule from a file using torch::jit::load().
        module = torch::jit::load(argv[1]);
        auto image_tensor = load_data(argv[2]);
    
        std::vector<torch::IValue> inputs{image_tensor};
        benchmark(module, inputs);
        auto outputs = module.forward(inputs);
      }
      catch (const c10::Error& e) {
        std::cerr << "error loading the model" << std::endl << e.what();
        return -1;
      }
    
      std::cout << "ok\n";
    }
    请将上述示例代码保存到本地的torch_app.cc文件。
  3. 编译代码。
    编译代码时,您需要链接libtorch相关库和SDK /usr/local/lib子目录下的SO文件(libtorch_addons.so和libral_base_context.so)。编译命令如下所示。
    TORCH_DIR=$(python3 -c "import torch; import os; print(os.path.dirname(torch.__file__))")
    g++ torch_app.cc -std=c++14 \\
        -D_GLIBCXX_USE_CXX11_ABI=0 \\
        -I ${TORCH_DIR}/include \\
        -I ${TORCH_DIR}/include/torch/csrc/api/include \\
        -Wl,--no-as-needed \\
        -L /usr/local/lib \\
        -L ${TORCH_DIR}/lib \\
        -l torch -l torch_cuda -l torch_cpu -l c10 -l c10_cuda \\
        -l torch_addons -l ral_base_context \\
        -o torch_app
    您可以根据实际情况修改如下参数:
    • torch_app.cc:推理代码的文件名。
    • /usr/local/lib:SDK的安装路径,通常无需修改。
    • torch_app:编译生成的可执行程序名。
    在某些版本的系统和编译器中,需要加上第6行的内容(-Wl,--no-as-needed \),以保证链接生效。
    注意
    • 根据您使用的libtorch ABI版本,正确配置GLIBCXX_USE_CXX11_ABI宏的值。二者的关系请参见下载并安装SDK
    • PAI-Blade敏捷版提供的CUDA 10.0的PyTorch是使用GCC 7.5编译的。如果使用CXX11 ABI,则务必确认GCC的版本。如果使用 Pre-CXX11 ABI,则不会有问题。
  4. 本地执行模型推理。
    您可以参考如下命令,使用编译好的可执行程序(torch_app)加载并执行PAI-Blade敏捷版优化好的示例模型(optimized_resnet50.pt)。
    export BLADE_REGION=<region>    # Region: cn-beijing, cn-shanghai for example.
    export BLADE_TOKEN=<token>
    export LD_LIBRARY_PATH=/usr/local/lib:${TORCH_DIR}/lib:${LD_LIBRARY_PATH}
    ./torch_app  optimized_resnet50.pt inputs.pth                      
    您需要根据实际情况替换以下参数:
    • <region>:PAI-Blade敏捷版支持的地域,需要加入PAI-Blade用户群获取该信息,用户群的二维码详情请参见获取Token
    • <token>:鉴权Token,需要加入PAI-Blade用户群获取该信息,用户群的二维码详情请参见获取Token
    • torch_app:上一步中编译好的可执行程序。
    • optimized_resnet50.pt:PAI-Blade敏捷版优化好的PyTorch模型,本文使用步骤1中下载的示例模型。
    • inputs.pth:步骤1中下载的测试数据。
    系统回显如下类似结果,表示模型已经顺利地开始执行了。
    finished computation at Wed Jan 27 20:03:38 2021
    
    elapsed time: 0.513882s
    avg latency: 25.6941ms
    ok