libtorch 上線之路-學習篇

最近在嘗試將組裏幾個pytorch的模型使用libtorch 做nn inference,折騰了幾個周,一路踩坑,終於把整個流程都打通了。因爲libtorch還比較新,網上經驗性的資料還比較少,現在寫下來總結一下經驗,分享一下。

0 環境

python 3.6
pytorch 1.3.1
g++ 5.3.1 # 要高於4.8,否則會報釋放內存的錯誤
CentOS Linux release 7.2 (Final)
cuda 9.2

1 入門

參考pytorch官網的教程《LOADING A TORCHSCRIPT MODEL IN C++》.
網上大部分的文檔都是對這篇教程的翻譯。文檔內容簡單,一步一步的來就行了。

2 初窺門徑

按照入門教程做完,只是知其然不知其所以然。接下來我們看看libtorch的原理。
libtorch c++和pytorch python這兩門語言能互通的關鍵點是一個叫torchscript的東西。TorchScript可以理解爲是pytorch的一個子集,能夠支持部分python原生代碼和部分pytorch接口,能夠被libtorch c++讀取和執行。
libtorch上線的原理就是將pytorch模型通過一定的方式轉換爲torchscript格式的模型,然後libtorch 讀取torchscript格式的模型並執行。
所以把torchscript學透就差不多可以了。《TORCHSCRIPT》 官方教程以及《TORCHSCRIPT BUILTINS》torchscript支持的pytorch API,仔細多讀幾遍,差不多能夠解決大部分的情況了。

3 打怪升級攢經驗

將pytorch模型轉爲TorchScript格式的流程就是根據TorchScript的規則適應性的修改pytorch代碼,並使用trace或者script模式將模型保存成TorchScript格式。

所以整個流程的核心其實就是能夠將各種python代碼修改成TorchScript能識別的格式。python這種具有各種包各種API的語言,大家經常會寫出一些“隨心所欲”的代碼;再加上寫python的人往往不關注效率二字;且libtorch的文檔比較少。種種原因導致修改的難度增加不少。當然也看模型複雜度,比較簡單的沒有什麼複雜處理的模型就沒什麼工作量了。

學完TorchScript的文檔,只能說是能夠應對一下常見的情況。想要做起來才能更得心應手,就需要你一個模型一個模型的打怪升級,總結經驗。

在這裏簡單說一些我踩過的坑和總結的一些技巧。

3.1 不要使用除了原生python和pytorch以外的庫

在nn inference的代碼中(pytorch一般是forward函數和它調用的一些函數),不要使用除了原生python和pytorch以外的庫,比如numpy什麼的,TorchScript一律不支持……
python array雖然也支持,但也儘量少用,總之一句話**,儘量用pytorch的各種API**。

3.2 儘量使用traced模式將模型保存成TorchScript格式

TorchScript一共有兩個模式將模型保存成TorchScript格式,traced和script。
script是直接將python代碼固化起來。traced模式是記錄python代碼走過的路徑,會進行一些優化操作(比如合併計算單元什麼的),雖然現在基本沒有啥優化操作。。但以後會有的。
所以在修改代碼的時候,建議trace模式爲主,script模式爲副。

3.3 保證結果正確性

保證正確性是做nn inference的首先前提
在這裏就是要保證TorchScript模型的結果跟訓練代碼的結果是一致的。
首先保證在python語言下結果是一致的,這個比較簡單,demo 代碼如下:

# 訓練代碼的結果
output = model(inputs)

# trace 模型的結果
trace_model = torch.jit.trace(model, (inputs))
trace_output = traced_model(inputs)

print(output.equal(trace_output))

然後還需要保證libtorch c++的結果跟python訓練代碼是一致的。
做法是將python中的輸入和輸出以一定格式寫文件,然後在libtorchc++中讀文件,再跟libtorch c++的結果進行對比。具體操作見 Load tensor from file in C++ fails

3.4 如何debug

這個是最煩心的。libtorch雖說是開源的,但是官方提供的庫是編譯好的,基本意味着gdb單步調試就很難了。只能用一些別的招。

  1. TorchScript格式的模型是可以使用unzip進行解壓的。解壓後的目錄大概如下:
project
│   constants.pkl
│   data.pkl 
│   version
└───code # TorchScript格式的代碼
└───data # 權值
└───constants # 常量

code文件夾就是我們需要的,這裏面可以看到TorchScript格式的python代碼。當3.3對比結果不正確或者以後調優的時候,這個就比較有用了

  1. pytorch github、論壇和教程。目前libtorch相關問題的資料基本都散落在這三個地方,耐心找吧……

3.5 一些libtorch api

libtorch c++ api文檔的不完善程度簡直令人髮指。下面列一些我在頭文件和網上找到的一些api用法

// tensor rand
torch::Tensor t = torch::rand({1, dim});
// Tensor賦值,注意類型
long sig_lens_arr[1] = {dim};
torch::Tensor t = torch::from_blob(sig_lens_arr, {1}, torch::kInt64);
// 獲得 Tensor 的大小
cout << t.sizes()[0] << " " << t.sizes()[1] << endl;
// 打印Tensor
cout << t << endl;
// 訪問Tensor內的值,注意類型
float*s_ptr = (float*)output_tensor.data_ptr();

結尾

把這篇博客裏的東西都喫透了差不多就可以出新手村了,下一篇我們將進入性能篇,未完待續。
對了,招實習生啊!

【實習】【騰訊北京AILAB】招募AI異構加速實習生
簡歷直接給負責人,給簡歷保證迅速反饋。
基本條件: 熟悉c++,至少實習6個月
工作內容:
1. 使用c++復現框架訓練的模型並進行CPU、GPU、ARM加速,達到上線的性能要求。
2. 調研各種inference框架並投入生產
加分項:
1、寫過或者維護過深度學習框架代碼; 
2、會CUDA 開發,能自己寫kernel,會用cublas,cudnn等庫; 
3、linux cpu c++編程能力,會寫avx、會用mkl;
4、熟悉深度學習計算過程
5、學習能力強,實習時間長
聯繫方式: [email protected]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章