libtorch使用筆記


libtorch

pytorch是一個強大的機器學習庫,其中集成了很多方法,但從python本身角度講,它的速度還不夠快。用pytorch官網的話說:

雖然對於許多需要動態性和易迭代性的場景來說,Python是一種合適且首選的語言,但在同樣的情況下,Python的這些特性恰恰是不利的。它常常應用於生產環境,這是一個低延遲和有嚴格部署要求的領域,一般選擇C++。

打ACM的時候,也是用C++寫一些比較惡心的算法居多,於是我也大膽地嘗試了用C++加載pytorch模型。

官網教程

下面是官網的教程

將Pytorch模型轉化為Torch Script

Torch Script可以完好的表達pytorch模型,而且也能被C++頭文件所理解。有兩種方法可以將pytorch模型轉換成TorchScript,Tracing和顯式注釋。有關這兩種方法的詳細使用請參考Torch Script reference

Tracing

這種方法需要你給模型傳入一個sample input,它會跟蹤在模型的forward方法中的過程。

import torch
import torchvision

# An instance of your model.
model = torchvision.models.resnet18()

# An example input you would normally provide to your model's forward() method.
example = torch.rand(1, 3, 224, 224)

# Use torch.jit.trace to generate a torch.jit.ScriptModule via tracing.
traced_script_module = torch.jit.trace(model, example)

Annotation

這種方法適合模型的forward方法不是那么顯而易見的,而需要一些流程控制的。

class MyModule(torch.nn.Module):
    def __init__(self, N, M):
        super(MyModule, self).__init__()
        self.weight = torch.nn.Parameter(torch.rand(N, M))

    def forward(self, input):
        if input.sum() > 0:
          output = self.weight.mv(input)
        else:
          output = self.weight + input
        return output

my_module = MyModule(10,20)
sm = torch.jit.script(my_module)

如果你想在模型的forward方法中使用TorchScrip尚不支持的一些python特性,使用@torch.jit.ignore來修飾。

導出TorchScript模型

就一句話:

traced_script_module.save("traced_resnet_model.pt")

這樣就和python沒啥關系了,開始大大方方的搞C++。

在C++中加載Model

一個最簡單的C++應用

下面代碼保存為example-app.cpp

#include <torch/script.h> // One-stop header.

#include <iostream>
#include <memory>

int main(int argc, const char* argv[]) {
  if (argc != 2) {
    std::cerr << "usage: example-app <path-to-exported-script-module>\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]);
  }
  catch (const c10::Error& e) {
    std::cerr << "error loading the model\n";
    return -1;
  }

  std::cout << "ok\n";
}

在這個最簡單的C++程序中,torch::jit::load()函數用來加載模形,參數為模型文件名,返回torch::jit::script::Module類,<torch/script.h>頭文件包含了需要的類和方法,下面我們來下載這個文件。

導入依賴

libtorch文件可以從官網下載,下載好對應版本后解壓縮,結構如下

libtorch/
  bin/
  include/
  lib/
  share/

CMakeLists.txt的寫法官網也有

cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(custom_ops)

find_package(Torch REQUIRED)

add_executable(example-app example-app.cpp)
target_link_libraries(example-app "${TORCH_LIBRARIES}")
set_property(TARGET example-app PROPERTY CXX_STANDARD 14)

項目結構:

example-app/
  CMakeLists.txt
  example-app.cpp

在bash中執行編譯命令(你需要有cmake工具,可以去官網下載,注意版本要和滿足CMakeLists.txtVERSION的條件)

mkdir build
cd build
cmake -DCMAKE_PREFIX_PATH=/path/to/libtorch ..
cmake --build . --config Release

一切順利的話你應該可以在build文件夾中看到你的程序的可執行文件了。

$ ./example-app
<path_to_model>/traced_resnet_model.pt
ok

運行模型

是時候你去掌握一些libtorch的用法了,模型已經導入成功,使用libtorch中的一些方法,你就可以像在python中一樣去跑你的模型了。

// Create a vector of inputs.
std::vector<torch::jit::IValue> inputs;
inputs.push_back(torch::ones({1, 3, 224, 224}));

// Execute the model and turn its output into a tensor.
at::Tensor output = module.forward(inputs).toTensor();
std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';

我的實踐

我在Ubuntu16\CentOS7\Windows10上都試了,只有Ubuntu一次成功了。

由於我以前用C++都是寫ACM的小代碼(with vim),所以調試起來都是g++到底的,沒有用過CMake,簡單學習了一下。在工程中,使用C++開發不可能每個單獨去編譯,這是十分低效的,cmake可以快速的生成開發文件,節省開發者時間。

基本用法網上比較統一,我不太懂其中原理,也沒什么新意,就不多說了。

Ubuntu

我在Ubuntu16.04環境下下載了官網的相應版本。然后完全按照流程進行,可以參考這里

wget https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-1.4.0%2Bcpu.zip

我修改了CMakeLists.txt,本想這樣不用在VScode的CMake工具中再配置什么其他參數,但是后來還是手動cmake的。

cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(custom_ops)

set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/libtorch") # added this, '/libtorch' is where the file unzipped
find_package(Torch REQUIRED)

add_executable(example-app example-app.cpp)
target_link_libraries(example-app "${TORCH_LIBRARIES}")
set_property(TARGET example-app PROPERTY CXX_STANDARD 11)

遇到問題

libtorch的系統問題

之前在Ubuntu下用了一個錯誤的libtorch,cmake沒有問題,make的時候全是錯誤。

cuda版本問題

我在windows下用的cuda10,然后去Ubuntu的時候還是選的cuda10,實際上那是一台不可用cuda的虛擬機,后來版本換成None就對了。這個錯誤比較明顯,因為它會提示與gpu有關的錯誤。

cmake版本問題

如大家所見,官網給的要求CMake版本在3.0及以上,我手動把CMakeLists.txt的版本要求降低到了已有的2.8,報錯!升級之后就可以了。

g++版本問題

在我的CentOS7服務器上,yum install gcc-g++,安裝的版本是4.*,也會產生錯誤,關於g++升級問題,切記千萬不要手賤先去去除軟連接(即不要隨便執行rm /usr/bin/g++ & rm /usr/bin/gcc)。

官方文檔

本文如有描述不當之處,歡迎指出!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM