0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何將pytorch的模型部署到c++平臺上的模型流程

新機器視覺 ? 來源:新機器視覺 ? 作者:新機器視覺 ? 2022-10-26 14:36 ? 次閱讀

導(dǎo)讀 本文主要講解如何將pytorch的模型部署到c++平臺上的模型流程,按順序分為四大塊詳細(xì)說明了模型轉(zhuǎn)換、保存序列化模型、C ++中加載序列化的PyTorch模型以及執(zhí)行Script Module。

最近因為工作需要,要把pytorch的模型部署到c++平臺上,基本過程主要參照官網(wǎng)的教學(xué)示例,期間發(fā)現(xiàn)了不少坑,特此記錄。

1.模型轉(zhuǎn)換

libtorch不依賴于python,python訓(xùn)練的模型,需要轉(zhuǎn)換為script model才能由libtorch加載,并進行推理。在這一步官網(wǎng)提供了兩種方法: 方法一:Tracing 這種方法操作比較簡單,只需要給模型一組輸入,走一遍推理網(wǎng)絡(luò),然后由torch.ji.trace記錄一下路徑上的信息并保存即可。示例如下:


importtorch importtorchvision #Aninstanceofyourmodel. model=torchvision.models.resnet18() #Anexampleinputyouwouldnormallyprovidetoyourmodel'sforward()method. example=torch.rand(1,3,224,224) #Usetorch.jit.tracetogenerateatorch.jit.ScriptModuleviatracing. traced_script_module=torch.jit.trace(model,example) 缺點是如果模型中存在控制流比如if-else語句,一組輸入只能遍歷一個分支,這種情況下就沒辦法完整的把模型信息記錄下來。 方法二:Scripting 直接在Torch腳本中編寫模型并相應(yīng)地注釋模型,通過torch.jit.script編譯模塊,將其轉(zhuǎn)換為ScriptModule。示例如下:

classMyModule(torch.nn.Module): def__init__(self,N,M): super(MyModule,self).__init__() self.weight=torch.nn.Parameter(torch.rand(N,M)) defforward(self,input): ifinput.sum()>0: output=self.weight.mv(input) else: output=self.weight+input returnoutput my_module=MyModule(10,20) sm=torch.jit.script(my_module)

forward方法會被默認(rèn)編譯,forward中被調(diào)用的方法也會按照被調(diào)用的順序被編譯

如果想要編譯一個forward以外且未被forward調(diào)用的方法,可以添加@torch.jit.export.

如果想要方法不被編譯,可使用[@torch.jit.ignore](https://link.zhihu.com/?target=https%3A//pytorch.org/docs/master/generated/torch.jit.ignore.html%23torch.jit.ignore)或者[@torch.jit.unused](https://link.zhihu.com/?target=https%3A//pytorch.org/docs/master/generated/torch.jit.unused.html%23torch.jit.unused)


#Samebehavioraspre-PyTorch1.2 @torch.jit.script defsome_fn(): return2 #Marksafunctionasignored,ifnothing #evercallsitthenthishasnoeffect @torch.jit.ignore defsome_fn2(): return2 #Aswithignore,ifnothingcallsitthenithasnoeffect. #Ifitiscalledinscriptitisreplacedwithanexception. @torch.jit.unused defsome_fn3(): importpdb;pdb.set_trace() return4 #Doesn'tdoanything,thisfunctionisalready #themainentrypoint @torch.jit.export defsome_fn4(): return2 在這一步遇到好多坑,主要原因可歸為一下兩點

1. 不支持的操作

TorchScript支持的操作是python的子集,大部分torch中用到的操作都可以找到對應(yīng)實現(xiàn),但也存在一些尷尬的不支持操作,詳細(xì)列表可見unsupported-ops(https://pytorch.org/docs/master/jit_unsupported.html#jit-unsupported),下面列一些我自己遇到的操作: 1)參數(shù)/返回值不支持可變個數(shù),例如


def__init__(self,**kwargs): 或者

ifoutput_flag==0: returnreshape_logits else: loss=self.loss(reshape_logits,term_mask,labels_id) returnreshape_logits,loss 2)各種iteration操作 eg1.

layers=[int(a)forainlayers] 報錯torch.jit.frontend.UnsupportedNodeError: ListComp aren’t supported 可以改成:

forkinrange(len(layers)): layers[k]=int(layers[k]) eg2.

seq_iter=enumerate(scores) try: _,inivalues=seq_iter.__next__() except: _,inivalues=seq_iter.next() eg3.

line=next(infile) 3)不支持的語句 eg1. 不支持continue torch.jit.frontend.UnsupportedNodeError: continue statements aren’t supported eg2. 不支持try-catch torch.jit.frontend.UnsupportedNodeError: try blocks aren’t supported eg3. 不支持with語句 4)其他常見op/module eg1. torch.autograd.Variable 解決:使用torch.ones/torch.randn等初始化+.float()/.long()等指定數(shù)據(jù)類型。 eg2. torch.Tensor/torch.LongTensor etc. 解決:同上 eg3. requires_grad參數(shù)只在torch.tensor中支持,torch.ones/torch.zeros等不可用 eg4. tensor.numpy() eg5. tensor.bool() 解決:tensor.bool()用tensor>0代替 eg6. self.seg_emb(seg_fea_ids).to(embeds.device) 解決:需要轉(zhuǎn)gpu的地方顯示調(diào)用.cuda() 總之一句話:除了原生python和pytorch以外的庫,比如numpy什么的能不用就不用,盡量用pytorch的各種API。

2. 指定數(shù)據(jù)類型

1)屬性,大部分的成員數(shù)據(jù)類型可以根據(jù)值來推斷,空的列表/字典則需要預(yù)先指定


fromtypingimportDict classMyModule(torch.nn.Module): my_dict:Dict[str,int] def__init__(self): super(MyModule,self).__init__() #Thistypecannotbeinferredandmustbespecified self.my_dict={} #Theattributetypehereisinferredtobe`int` self.my_int=20 defforward(self): pass m=torch.jit.script(MyModule()) 2)常量,使用_Final_關(guān)鍵字

try: fromtyping_extensionsimportFinal except: #Ifyoudon'thave`typing_extensions`installed,youcanusea #polyfillfrom`torch.jit`. fromtorch.jitimportFinal classMyModule(torch.nn.Module): my_constant:Final[int] def__init__(self): super(MyModule,self).__init__() self.my_constant=2 defforward(self): pass m=torch.jit.script(MyModule()) 3)變量。默認(rèn)是tensor類型且不可變,所以非tensor類型必須要指明

defforward(self,batch_size:int,seq_len:int,use_cuda:bool): 方法三:Tracing and Scriptin混合 一種是在trace模型中調(diào)用script,適合模型中只有一小部分需要用到控制流的情況,使用實例如下:

importtorch @torch.jit.script deffoo(x,y): ifx.max()>y.max(): r=x else: r=y returnr defbar(x,y,z): returnfoo(x,y)+z traced_bar=torch.jit.trace(bar,(torch.rand(3),torch.rand(3),torch.rand(3))) 另一種情況是在script module中用tracing生成子模塊,對于一些存在script module不支持的python feature的layer,就可以把相關(guān)layer封裝起來,用trace記錄相關(guān)layer流,其他layer不用修改。使用示例如下:

importtorch importtorchvision classMyScriptModule(torch.nn.Module): def__init__(self): super(MyScriptModule,self).__init__() self.means=torch.nn.Parameter(torch.tensor([103.939,116.779,123.68]) .resize_(1,3,1,1)) self.resnet=torch.jit.trace(torchvision.models.resnet18(), torch.rand(1,3,224,224)) defforward(self,input): returnself.resnet(input-self.means) my_script_module=torch.jit.script(MyScriptModule())

2.保存序列化模型

如果上一步的坑都踩完,那么模型保存就非常簡單了,只需要調(diào)用save并傳遞一個文件名即可,需要注意的是如果想要在gpu上訓(xùn)練模型,在cpu上做inference,一定要在模型save之前轉(zhuǎn)化,再就是記得調(diào)用model.eval(),形如


gpu_model.eval() cpu_model=gpu_model.cpu() sample_input_cpu=sample_input_gpu.cpu() traced_cpu=torch.jit.trace(traced_cpu,sample_input_cpu) torch.jit.save(traced_cpu,"cpu.pth") traced_gpu=torch.jit.trace(traced_gpu,sample_input_gpu) torch.jit.save(traced_gpu,"gpu.pth")

3.C++ load訓(xùn)練好的模型

要在C ++中加載序列化的PyTorch模型,必須依賴于PyTorch C ++ API(也稱為LibTorch)。libtorch的安裝非常簡單,只需要在pytorch官網(wǎng)下載對應(yīng)版本,解壓即可。會得到一個結(jié)構(gòu)如下的文件夾。


libtorch/ bin/ include/ lib/ share/ 然后就可以構(gòu)建應(yīng)用程序了,一個簡單的示例目錄結(jié)構(gòu)如下:

example-app/ CMakeLists.txt example-app.cpp example-app.cpp和CMakeLists.txt的示例代碼分別如下:

#include//One-stopheader. #include #include intmain(intargc,constchar*argv[]){ if(argc!=2){ std::cerr< "; return-1; } torch::Modulemodule; try{ //DeserializetheScriptModulefromafileusingtorch::load(). module=torch::load(argv[1]); } catch(constc10::Error&e){ std::cerr<

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/文件夾中構(gòu)建應(yīng)用程序啦:

mkdir build cd build cmake -DCMAKE_PREFIX_PATH=/path/to/libtorch .. cmake --build . --config Release 其中/path/to/libtorch是之前下載后的libtorch文件夾所在的路徑。這一步如果順利能夠看到編譯完成100%的提示,下一步運行編譯生成的可執(zhí)行文件,會看到“ok”的輸出,可喜可賀!

4. 執(zhí)行Script Module

終于到最后一步啦!下面只需要按照構(gòu)建輸入傳給模型,執(zhí)行forward就可以得到輸出啦。一個簡單的示例如下:


//Createavectorofinputs. std::vectorinputs; inputs.push_back(torch::ones({1,3,224,224})); //Executethemodelandturnitsoutputintoatensor. at::Tensoroutput=module.forward(inputs).toTensor(); std::cout<

torch::tensor(input_list[j]).to(at::kLong).resize_({batch,128}).clone() //torch::tensor對應(yīng)pytorch的torch.tensor;at::kLong對應(yīng)torch.int64;resize_對應(yīng)resize 最后check一下確保c++端的輸出和pytorch是一致的就大功告成啦~ 踩了無數(shù)坑,薅掉了無數(shù)頭發(fā),很多東西也是自己一點點摸索的,如果有錯誤歡迎指正!
審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2090

    瀏覽量

    73404
  • 模型
    +關(guān)注

    關(guān)注

    1

    文章

    3059

    瀏覽量

    48575
  • pytorch
    +關(guān)注

    關(guān)注

    2

    文章

    795

    瀏覽量

    13079

原文標(biāo)題:C++平臺PyTorch模型部署流程,踩坑心得實錄

文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    如何使用OpenVINO C++ API部署FastSAM模型

    象的位置和邊界。本文介紹如何使用 OpenVINO C++ API 部署 FastSAM 模型,以實現(xiàn)快速高效的語義分割。在前文中我們發(fā)表了《基于 OpenVINO Python A
    的頭像 發(fā)表于 11-17 09:53 ?783次閱讀
    如何使用OpenVINO <b class='flag-5'>C++</b> API<b class='flag-5'>部署</b>FastSAM<b class='flag-5'>模型</b>

    如何將AI模型部署嵌入式系統(tǒng)中

    本期我們分享主題是如何將 AI 模型部署嵌入式系統(tǒng)中,下一期介紹如何在 RT-Thread 操作系統(tǒng)上運行 Mnist Demo(手寫數(shù)
    發(fā)表于 12-14 07:55

    Pytorch模型如何通過paddlelite部署嵌入式設(shè)備?

    Pytorch模型如何通過paddlelite部署嵌入式設(shè)備?
    發(fā)表于 12-23 09:38

    pytorch模型轉(zhuǎn)化為onxx模型的步驟有哪些

    首先pytorch模型要先轉(zhuǎn)化為onxx模型,然后從onxx模型轉(zhuǎn)化為rknn模型直接轉(zhuǎn)化會出現(xiàn)如下問題,環(huán)境都是正確的,論壇詢問后也沒給出
    發(fā)表于 05-09 16:36

    通過Cortex來非常方便的部署PyTorch模型

    的工作。那么,問題是如何將 RoBERTa 部署為一個 JSON API,而不需要手動滾動所有這些自定義基礎(chǔ)設(shè)施? PyTorch 模型
    發(fā)表于 11-01 15:25

    Pytorch模型轉(zhuǎn)換為DeepViewRT模型時出錯怎么解決?

    我最終可以在 i.MX 8M Plus 處理器上部署 .rtm 模型。 我遵循了 本指南,我 Pytorch 模型轉(zhuǎn)換為 ONNX
    發(fā)表于 06-09 06:42

    如何使用TensorFlow神經(jīng)網(wǎng)絡(luò)模型部署移動或嵌入式設(shè)備上

    有很多方法可以經(jīng)過訓(xùn)練的神經(jīng)網(wǎng)絡(luò)模型部署移動或嵌入式設(shè)備上。不同的框架在各種平臺上支持Arm,包括TensorFlow、
    發(fā)表于 08-02 06:43

    如何將PyTorch模型與OpenVINO trade結(jié)合使用?

    無法確定如何轉(zhuǎn)換 PyTorch 掩碼 R-CNN 模型以配合OpenVINO?使用。
    發(fā)表于 08-15 07:04

    pytorch模型轉(zhuǎn)換需要注意的事項有哪些?

    和記錄張量上的操作,不會記錄任何控制流操作。 為什么不能是GPU模型? 答:BMNETP的編譯過程不支持。 如何將GPU模型轉(zhuǎn)成CPU模型? 答:在加載
    發(fā)表于 09-18 08:05

    使用CortexPyTorch模型部署生產(chǎn)中

    從 NLP 計算機視覺都可以通過 Cortex來非常方便的部署PyTorch模型。作者:Caleb Kaiser編譯:ronghuaiyang首發(fā):AI公園公眾號
    的頭像 發(fā)表于 12-10 20:14 ?394次閱讀

    如何將Pytorch自訓(xùn)練模型變成OpenVINO IR模型形式

    本文章依次介紹如何將Pytorch自訓(xùn)練模型經(jīng)過一系列變換變成OpenVINO IR模型形式,而后使用OpenVINO Python AP
    的頭像 發(fā)表于 06-07 09:31 ?1785次閱讀
    <b class='flag-5'>如何將</b><b class='flag-5'>Pytorch</b>自訓(xùn)練<b class='flag-5'>模型</b>變成OpenVINO IR<b class='flag-5'>模型</b>形式

    如何部署ML模型Google云平臺

    實踐中的機器學(xué)習(xí):在 Google 云平臺上部署 ML 模型
    的頭像 發(fā)表于 07-05 16:30 ?611次閱讀
    如何<b class='flag-5'>部署</b>ML<b class='flag-5'>模型</b><b class='flag-5'>到</b>Google云<b class='flag-5'>平臺</b>

    TorchVision框架下模型導(dǎo)出并部署ONNXRUNTIME C++流程解析

    ONNXRUNTIME是主流的深度學(xué)習(xí)部署框架之一,支持ONNX格式模型在CPU、GPU、ARM等不同硬件平臺上加速推理,支持C++、Python、Java、
    的頭像 發(fā)表于 07-13 14:46 ?1228次閱讀
    TorchVision框架下<b class='flag-5'>模型</b>導(dǎo)出并<b class='flag-5'>部署</b><b class='flag-5'>到</b>ONNXRUNTIME <b class='flag-5'>C++</b>全<b class='flag-5'>流程</b>解析

    基于OpenVINO C++ API部署RT-DETR模型

    應(yīng)用中,我們?yōu)榱伺c當(dāng)前軟件平臺集成更多會采用 C++ 平臺,因此在本文中,我們基于 OpenVINO C++ API 向大家展示了不包含后
    的頭像 發(fā)表于 11-03 14:30 ?706次閱讀
    基于OpenVINO <b class='flag-5'>C++</b> API<b class='flag-5'>部署</b>RT-DETR<b class='flag-5'>模型</b>

    基于OpenVINO C# API部署RT-DETR模型

    Python 和 C++ API 向大家展示了的 RT-DETR 模型部署流程,并分別展示了是否包含后處理的模型
    的頭像 發(fā)表于 11-10 16:59 ?661次閱讀
    基于OpenVINO <b class='flag-5'>C</b># API<b class='flag-5'>部署</b>RT-DETR<b class='flag-5'>模型</b>