小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

基于C 的PyTorch模型部署

 aideshizhe0 2023-04-30 發(fā)布于河南

PyTorch

Author:louwill

Machine Learning Lab

引言

     PyTorch作為一款端到端的深度學(xué)習(xí)框架,在1.0版本之后已具備較好的生產(chǎn)環(huán)境部署條件。除了在web端撰寫(xiě)REST API進(jìn)行部署之外(參考),軟件端的部署也有廣泛需求。尤其是最近發(fā)布的1.5版本,提供了更為穩(wěn)定的C++前端API。

     工業(yè)界與學(xué)術(shù)界最大的區(qū)別在于工業(yè)界的模型需要落地部署,學(xué)界更多的是關(guān)心模型的精度要求,而不太在意模型的部署性能。一般來(lái)說(shuō),我們用深度學(xué)習(xí)框架訓(xùn)練出一個(gè)模型之后,使用Python就足以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的推理演示了。但在生產(chǎn)環(huán)境下,Python的可移植性和速度性能遠(yuǎn)不如C++。所以對(duì)于深度學(xué)習(xí)算法工程師而言,Python通常用來(lái)做idea的快速實(shí)現(xiàn)以及模型訓(xùn)練,而用C++作為模型的生產(chǎn)工具。目前PyTorch能夠完美的將二者結(jié)合在一起。實(shí)現(xiàn)PyTorch模型部署的核心技術(shù)組件就是TorchScript和libtorch。

     所以基于PyTorch的深度學(xué)習(xí)算法工程化流程大體如下圖所示:

圖片

TorchScript

     TorchScript可以視為PyTorch模型的一種中間表示,TorchScript表示的PyTorch模型可以直接在C++中進(jìn)行讀取。PyTorch在1.0版本之后都可以使用TorchScript的方式來(lái)構(gòu)建序列化的模型。TorchScript提供了Tracing和Script兩種應(yīng)用方式。

     Tracing應(yīng)用示例如下:

class MyModel(torch.nn.Module):    def __init__(self):        super(MyModel, self).__init__() self.linear = torch.nn.Linear(4, 4)
    def forward(self, x, h):        new_h = torch.tanh(self.linear(x) + h) return new_h, new_h
# 創(chuàng)建模型實(shí)例 my_model = MyModel()# 輸入示例x, h = torch.rand(34), torch.rand(34)# torch.jit.trace方法對(duì)模型構(gòu)建TorchScripttraced_model = torch.jit.trace(my_model, (x, h))# 保存轉(zhuǎn)換后的模型traced_model.save('model.pt')

     在這段代碼中,我們先是定義了一個(gè)簡(jiǎn)單模型并創(chuàng)建模型實(shí)例,然后給定輸入示例,Tracing方法最關(guān)鍵的一步在于使用torch.jit.trace方法對(duì)模型進(jìn)行TorchScript轉(zhuǎn)化。我們可以獲得轉(zhuǎn)化后的traced_model對(duì)象獲得其計(jì)算圖屬性和代碼屬性。計(jì)算圖屬性:

print(traced_model.graph)
graph(%self.1 : __torch__.torch.nn.modules.module.___torch_mangle_1.Module,      %input : Float(3, 4),      %h : Float(3, 4)):  %19 : __torch__.torch.nn.modules.module.Module = prim::GetAttr[name='linear'](%self.1)  %21 : Tensor = prim::CallMethod[name='forward'](%19, %input)  %12 : int = prim::Constant[value=1]() # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0  %13 : Float(3, 4) = aten::add(%21, %h, %12) # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0  %14 : Float(3, 4) = aten::tanh(%13) # /var/lib/jenkins/workspace/beginner_source/Intro_to_TorchScript_tutorial.py:188:0  %15 : (Float(3, 4), Float(3, 4)) = prim::TupleConstruct(%14, %14) return (%15)

代碼屬性:

print(traced_cell.code)

def forward(self,    input: Tensor,    h: Tensor) -> Tuple[Tensor, Tensor]:  _0 = torch.add((self.linear).forward(input, ), h, alpha=1)  _1 = torch.tanh(_0) return (_1, _1)

     這樣我們就可以將整個(gè)模型都保存到硬盤(pán)上了,并且經(jīng)過(guò)這種方式保存下來(lái)的模型可以加載到其他其他語(yǔ)言環(huán)境中。

     TorchScript的另一種實(shí)現(xiàn)方式是Script的方式,可以算是對(duì)Tracing方式的一種補(bǔ)充。當(dāng)模型代碼中含有if或者for-loop等控制流程序時(shí),使用Tracing方式是無(wú)效的,這時(shí)候可以采用Script方式來(lái)進(jìn)行實(shí)現(xiàn)TorchScript。實(shí)現(xiàn)方法跟Tracing差異不大,關(guān)鍵在于把jit.tracing換成jit.script方法,示例如下。

scripted_model = torch.jit.script(MyModel)scripted_model.save('model.pt')

     除了Tracing和Script之外,我們也可以混合使用這兩種方式,這里不做詳述。總之,TorchScript為我們提供了一種表示形式,可以對(duì)代碼進(jìn)行編譯器優(yōu)化以提供更有效的執(zhí)行。

libtorch

     在Python環(huán)境下對(duì)訓(xùn)練好的模型進(jìn)行轉(zhuǎn)換之后,我們需要C++環(huán)境下的PyTorch來(lái)讀取模型并進(jìn)行編譯部署。這種C++環(huán)境下的PyTorch就是libtorch。因?yàn)閘ibtorch通常用來(lái)作為PyTorch模型的C++接口,libtorch也稱之為PyTorch的C++前端。

     我們可以直接從PyTorch官網(wǎng)下載已經(jīng)編譯好的libtorch安裝包,當(dāng)然也可以下載源碼自行進(jìn)行編譯。這里需要注意的是,安裝的libtorch版本要與Python環(huán)境下的PyTorch版本一致。

圖片

     安裝好libtorch后可簡(jiǎn)單測(cè)試下是否正常。比如我們用TorchScript轉(zhuǎn)換一個(gè)預(yù)訓(xùn)練模型,示例如下:

import torchimport torchvision.models as modelsvgg16 = models.vgg16()example = torch.rand(1, 3, 224, 224).cuda() model = model.eval()traced_script_module = torch.jit.trace(model, example)output = traced_script_module(torch.ones(1,3,224,224).cuda())traced_script_module.save('vgg16-trace.pt')print(output)

輸出為:

tensor([[ -0.8301-35.609512.4716]], device='cuda:0',        grad_fn=<AddBackward0>)

     然后切換到C++環(huán)境,編寫(xiě)CmakeLists文件如下:

cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)project(libtorch_test)find_package(Torch REQUIRED)message(STATUS 'Pytorch status:')message(STATUS 'libraries: ${TORCH_LIBRARIES}')add_executable(libtorch_test test.cpp)target_link_libraries(libtorch_test '${TORCH_LIBRARIES}')set_property(TARGET libtorch_test PROPERTY CXX_STANDARD 11)

     繼續(xù)編寫(xiě)test.cpp代碼如下:

#include 'torch/script.h'#include 'torch/torch.h'#include <iostream>#include <memory>using namespace std;
int main(int argc, const char* argv[]){    if (argc != 2) {        std::cerr << 'usage: example-app <path-to-exported-script-module>\n';        return -1; }
    // 讀取TorchScript轉(zhuǎn)化后的模型    torch::jit::script::Module module;    try {        module = torch::jit::load(argv[1]); }
    catch (const c10::Error& e) {        std::cerr << 'error loading the model\n';        return -1; }
    module->to(at::kCUDA);    assert(module != nullptr); std::cout << 'ok\n';
    // 構(gòu)建示例輸入    std::vector<torch::jit::IValue> inputs; inputs.push_back(torch::ones({1, 3, 224, 224}).to(at::kCUDA));
    // 執(zhí)行模型推理并輸出tensor    at::Tensor output = module->forward(inputs).toTensor(); std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';}

     編譯test.cpp并執(zhí)行,輸出如下。對(duì)比Python環(huán)境下的的運(yùn)行結(jié)果,可以發(fā)現(xiàn)基本是一致的,這也說(shuō)明當(dāng)前環(huán)境下libtorch安裝沒(méi)有問(wèn)題。

ok-0.8297-35.604812.4823[Variable[CUDAFloatType]{1,3}]

完整部署流程

     通過(guò)前面對(duì)TorchScript和libtorch的描述,其實(shí)我們已經(jīng)基本將PyTorch的C++部署已經(jīng)基本講到了,這里我們?cè)賮?lái)完整的理一下整個(gè)流程?;贑++的PyTorch模型部署流程如下。

第一步:

     通過(guò)torch.jit.trace方法將PyTorch模型轉(zhuǎn)換為T(mén)orchScript,示例如下:

import torchfrom torchvision.models import resnet18model =resnet18()example = torch.rand(1, 3, 224, 224)tracing.traced_script_module = torch.jit.trace(model, example)

第二步:

     將TorchScript序列化為.pt模型文件。

traced_script_module.save('traced_resnet_model.pt')

第三步:

     在C++中導(dǎo)入序列化之后的TorchScript模型,為此我們需要分別編寫(xiě)包含調(diào)用程序的cpp文件、配置和編譯用的CMakeLists.txt文件。CMakeLists.txt文件示例內(nèi)容如下:

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)

     包含模型調(diào)用程序的example-app.cpp示例編碼如下:

#include <torch/script.h> // torch頭文件.#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 {    // 反序列化:導(dǎo)入TorchScript模型    module = torch::jit::load(argv[1]); }
  catch (const c10::Error& e) {    std::cerr << 'error loading the model\n';    return -1; } std::cout << 'ok\n';}

     兩個(gè)文件編寫(xiě)完成之后便可對(duì)其執(zhí)行編譯:

mkdir example_testcd example_testcmake -DCMAKE_PREFIX_PATH=/path/to/libtorch ..cmake --example_test . --config Release

第四步:

給example-app.cpp添加模型推理代碼并執(zhí)行:

std::vector<torch::jit::IValue> inputs;inputs.push_back(torch::ones({13224224}));// 執(zhí)行推理并將模型轉(zhuǎn)化為T(mén)ensoroutput = module.forward(inputs).toTensor();std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';

     以上便是C++中部署PyTorch模型的全過(guò)程,相關(guān)教程可參考PyTorch官方:

https://pytorch.org/tutorials/

參考資料:

https://pytorch.org/tutorials/

https://pytorch.org/features/

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多