在C++部屬pytorch模型

這一篇將介紹我在C++部屬pytorch模型的方法,作法是參考官方文件。考量讓程式能夠同時在Windows以及Linux上運行,程式是透過CMake建置,並分別透過VScode的WSL(Windows)以及Bash(Linux)。

將模型轉換為與語言無關的Torchscript模型

追求高計算效率的科學或是工程程式,C++ 經常被選擇的程式語言(reference)。欲使Pytorch模型可以在C++ 中使用,則可藉由Pytorch官方提供的JIT模組,將pytorch模型轉換為與語言無關的Torchscript模型。

1
2
3
4
#訓練完模型將模型轉換為Torchscript模型
PATH= "model_jit.pth"
traced_net=torch.jit.trace(model, torch.randn(1,6724).to(device))
torch.jit.save(traced_net, PATH)

環境setup

  • 安裝 Pytorch C++ API (reference)
  • 目錄
    1
    2
    repository$ ls
    CMakeLists.txt Makefile Source.cpp #工作目錄下三個檔案
  • CMakeLists.txt
    1
    2
    3
    4
    5
    6
    7
    8
    9
    cmake_minimum_required(VERSION 3.2)
    project(my_project)
    set(CMAKE_PREFIX_PATH /path/to/libtorch)
    find_package(Torch REQUIRED)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")
    add_executable(${PROJECT_NAME} Source.cpp)
    target_link_libraries(${PROJECT_NAME} "${TORCH_LIBRARIES}")
    set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14)
    set(CMAKE_BUILD_TYPE Debug) # for gdb tool
  • Makefile(用以簡化反覆輸入相同的指令)
    1
    2
    3
    4
    .PHONY: default
    default:
    rm -rf build
    mkdir build
  • .cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #include <iostream>
    #include <math.h>
    #include <fstream>
    #include <string>
    #include <torch/torch.h>
    #include <torch/script.h>
    using namespace std;

    int main(){
    torch::jit::script::Module model=torch::jit::load("/path/to/model_jit.pth");
    double test[2][2]={0.0};
    double u_st[1][4]={{1.0 2.0 3.0 4.0}};
    auto options = torch::TensorOptions().dtype(torch::kFloat32);
    torch::Tensor x, out;
    vector<torch::jit::IValue> input;

    /*(input) array into tensor into vector*/
    x=torch::from_blob(u_st, {1,4}, options);
    input.clear();
    input.push_back(x);

    /*input into output(tensor)*/
    out=model.forward(input).toTensor();

    /*(output)tensor into 2D-array*/
    cout<< "out[0][j]: "<<endl;
    for(int i=0; i<2; i++){
    for(int j=0; j<2; j++){
    test[i][j]=out[0][i*(2)+j].item<float>();
    }
    }
    return 0;

    }

Build and run

  • Build
    1
    2
    3
    4
    repository$ make
    repository$ cd build
    repository/build$ cmake ..
    repository/build$ cmake --build . --config Release
  • Run
    1
    repository/build$ ./my_project
    or run in gdb
    1
    2
    repository/build$ gdb ./my_project
    (gdb) run

浮點數精度

Pytorch的模型預設的data type是float or Float32,是32-bit 的floating point,如果C++中使用的data type是double or Float64在運算時會出現錯誤。解決此問題需要改動以上程式3個地方。

  • Torchscript模型的轉換需加入
    1
    2
    3
    4
    PATH= "model_jit.pth"
    traced_net=torch.jit.trace(model, torch.randn(1,6724).to(device))
    traced_net.to(torch.float64) #轉成double
    torch.jit.save(traced_net, PATH)
  • .cpp
    1
    auto options = torch::TensorOptions().dtype(torch::kFloat64); //32改成64
  • .cpp
    1
    test[i][j]=out[0][i*(2)+j].item<double>(); // float改成double

是否能在其他語言中使用Pytorch模型?

以下是Pytorch documentation下方對於Torchscript的描述:

TorchScript is a way to create serializable and optimizable models from PyTorch code. Any TorchScript program can be saved from a Python process and loaded in a process where there is no Python dependency.

免除對於python的相依,Torchscript連結到其他語言需要 front-end API(Application Programming Interface),目前在官方文件中僅有C++,所以我的理解是目前還無法藉由相同方法在其他語言使用pytorch model。

Python vs C++ 作為pytorch前端

藉由官方所提供的工具可以將整個過程,包括訓練過程都放到C++中,但若沒有強烈的需求官方建議不需要這麼做(link),pytorch以python作為前端能夠維持較良好的使用者體驗品質,而因為pytorch即便以python作為前端,需要計算需求時就會呼叫C++ 讓C++ 去完成,所以相比以C++作為前端,兩者在計算效率上並沒有太多差異。

Alternatives

  • ONNX

    ONNX format models can painlessly be exported from PyTorch, and experiments have shown ONNX Runtime to be outperforming TorchScript.