在C++部屬pytorch模型
這一篇將介紹我在C++部屬pytorch模型的方法,作法是參考官方文件。考量讓程式能夠同時在Windows以及Linux上運行,程式是透過CMake建置,並分別透過VScode的WSL(Windows)以及Bash(Linux)。
將模型轉換為與語言無關的Torchscript模型
追求高計算效率的科學或是工程程式,C++ 經常被選擇的程式語言(reference)。欲使Pytorch模型可以在C++ 中使用,則可藉由Pytorch官方提供的JIT模組,將pytorch模型轉換為與語言無關的Torchscript模型。
1 | #訓練完模型將模型轉換為Torchscript模型 |
環境setup
- 安裝 Pytorch C++ API (reference)
- 目錄
1
2repository$ ls
CMakeLists.txt Makefile Source.cpp #工作目錄下三個檔案 - CMakeLists.txt
1
2
3
4
5
6
7
8
9cmake_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
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
4repository$ make
repository$ cd build
repository/build$ cmake ..
repository/build$ cmake --build . --config Release - Runor run in
1
repository/build$ ./my_project
gdb
1
2repository/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
4PATH= "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.