<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          基于TensorRT的BERT推斷加速與服務(wù)部署

          共 13620字,需瀏覽 28分鐘

           ·

          2021-10-15 09:30

          BERT的出現(xiàn)真是廣大NLPer的福音,在很多任務(wù)上能取得顯著提升。不例外,作者在工作過程中也使用了BERT進(jìn)行下游任務(wù)訓(xùn)練,但在感嘆BERT真香的時候,它及其漫長的推斷時間讓人感到很為難。本文就記錄了在使用tensorRT部署B(yǎng)ERT時候的各種坑。話不多說,先給下最終模型推斷時間對比(如下面表格所示),然后開始我們的填坑記。

          max_seqbatch_size15102040100
          128Tensorflow(ms)20244576130300
          128tensorRT(ms)2.25.27.210.11951

          實(shí)戰(zhàn)系列篇章中主要會分享,解決實(shí)際問題時的過程、遇到的問題或者使用的工具等等。如問題分解、bug排查、模型部署等等。已更新的文章根據(jù)篇章目錄查看,相關(guān)代碼實(shí)現(xiàn)開源在:https://github.com/wellinxu/nlp_store ,更多內(nèi)容關(guān)注知乎專欄(或微信公眾號):NLP雜貨鋪。

          • 基本依賴
          • 自尋坑路
          • TensorRT
            • 'UFF'模型轉(zhuǎn)換錯誤
          • BERT in TensorRT
            • 'time out'demo模型特難下載
            • 順利運(yùn)行demo推斷
            • 'additional_dict'模型中包含訓(xùn)練時的參數(shù)
            • 'cls_squad_output_weights'模型中參數(shù)名稱不一致
            • 'ascii'中文讀取報錯
            • 模型結(jié)構(gòu)與demo不同
            • 'nan'batch大小的配置問題
            • tensorflow與tensorRT的推斷時間對比
          • tensorRT server for BERT
            • 'segmentation'cuda與flask的沖突
            • tensorrt模型文件的確認(rèn)
            • 'deserialize'tensorrtserver版本問題
            • 'CustomEmbLayerNormPluginDynamic'插件缺失
            • config.pbtxt配置文件不對
          • Client
            • tensorrtserver.api下載安裝
            • 'dimension'batch大小的配置問題
          • 上線
            • Serialization Error
          • 總結(jié)
          • 參考

          基本依賴

          • [ ] python
          • [ ] git
          • [ ] gpu
          • [ ] nvidia-docker
          • [ ] bert的checkout模型

          自尋坑路

          那天接口調(diào)用方告訴我,我的接口超時了要優(yōu)化下。從使用BERT開始我就知道,總會有這一天的,而現(xiàn)在終于來了。在一開始部署服務(wù)的時候,就直接上了GPU,對于一般調(diào)用,雖然慢了點(diǎn),但也不至于超時。但被新業(yè)務(wù)調(diào)用后,處理的樣本量明顯增加,特別容易出現(xiàn)超時的現(xiàn)象。沒辦法,自己約的,呸,自己選的路,再艱難也得先看看別人趟的水,然后再決定走不走。既然需求已經(jīng)提了,我當(dāng)然立刻行動起來,根據(jù)項目特性,先優(yōu)化了一波流程,讓整體速度提升了4倍左右,之前timeout的樣例都通過了,先部署起來給下游用。雖然提升了4倍速度,但大樣本依然游走在timeout的邊緣,如果遇到更大的樣本,就...。
          為了看看前人趟的水,就來知乎進(jìn)行了搜索,然后得到了下面幾篇文章。

          《從零開始學(xué)習(xí)自然語言處理(NLP)》-BERT推理加速實(shí)踐(6)【1】
          《從零開始學(xué)習(xí)自然語言處理(NLP)》-BERT模型推理加速總結(jié)(5)【2】
          加速 BERT 模型有多少種方法?從架構(gòu)優(yōu)化、模型壓縮到模型蒸餾,最新進(jìn)展詳解!【3】
          NVIDIA發(fā)布TensorRT 6,突破BERT-Large推理10毫秒大關(guān)【4】

          從結(jié)果看,有這么幾種方式:縮短max_seq,合并請求組成大batch,替換模型(蒸餾/縮減層數(shù)等),換成float16精度,使用tensorflow的xla,使用tensorRT??s短max_seq首先被排除了,因?yàn)檫@個項目在處理過程中,要對所有的文本進(jìn)行處理,縮短seq等于增加了樣本量,所以不適合我們項目。組成大batch也不行,我們的一次請求都至少40個樣本,在樣本量超過40之后,batch的增加與時間的增加基本上是線性的,所以也不適合。至于替換模型,之前嘗試過tiny版的albert,速度肯定有提升,但準(zhǔn)確率降了5個點(diǎn),接受不了。后面的幾個方法,tensorRT同時包含了所有優(yōu)點(diǎn),so,基于tensorRT部署B(yǎng)ERT服務(wù),坑從此開始。

          TensorRT

          tensorRT【5】是什么,不知道,沒聽過,不管了,先按照說明【6】把tensorrt安裝下,在我tensorflow14的docker容器中一頓操作,哎,木報錯,順利安裝完。然后需要把模型轉(zhuǎn)為tensorRT形式,順利找到轉(zhuǎn)tensorflow模型的文檔【7】,當(dāng)然checkout模型是不能直接轉(zhuǎn)的,事先要轉(zhuǎn)為‘frozen TensorFlow model’格式,這個在【7】中也有提示,也可以自行百度/google尋找教程。

          'UFF'模型轉(zhuǎn)換錯誤

          順利轉(zhuǎn)完模型后,需要轉(zhuǎn)為uff文件,這時坑開始來了,出現(xiàn)了一個它認(rèn)識我我不認(rèn)識它的錯誤(這個錯誤到寫文章時都沒解決,有一個原因是后來沒有走這條路)。只能再去找前人,文章【8】中顯示,nvidia專門對BERT進(jìn)行過優(yōu)化,是有demo的,一翻波折之后,終于找到了官方demo。

          BERT in TensorRT

          在tensortRT的官方github上一開始并沒有找到BERT的demo,后來發(fā)現(xiàn)在5.1與6.0分支【9】中都有BERT的demo,聰明的我認(rèn)為新版本應(yīng)該更好些(也許選擇5.1,會少走一些彎路,但我不想再去找坑了),于是重新開始了尋坑之旅,這樣第一行代碼出現(xiàn)了:

          git?clone?-b?release/6.0?https://github.com/NVIDIA/TensorRT.git

          根據(jù)【9】中python的提示,依次運(yùn)行:

          cd?TensorRT/demo/BERT
          sh?python/create_docker_container.sh

          'time out'demo模型特難下載

          在TensorRT/demo/BERT/python目錄下有readme說明文檔,根據(jù)說明準(zhǔn)備環(huán)境,第一步克隆代碼已經(jīng)完成,第二步建立鏡像,時間稍微有點(diǎn)久,但還算順利,第三步在鏡像中編譯插件/下載調(diào)試過的模型(因?yàn)槭峭暾膁emo,所以模型都是有demo的),其中模型下載可以根據(jù)需求選擇base/large,max_seq的大小,以及float32/float16精度,插件編譯得還比較順利,就是模型下載得太慢了,十幾k每秒,也不知道多大,那就等著,自己再去看看不知道是什么的TensorRT。直到下班,還沒下好,沒事明天早上再來看,結(jié)果第二天過來看,告訴我下載失敗,好吧重新下,5個小時后又下載失敗,好吧重新下......終于下載了3天得到了base_fp16_384的模型。反應(yīng)慢的我這時候想起,我們項目中的長度是128,最好弄個128的模型,這樣方便對比推斷的時間,所以在后臺重新下載128的模型,自己先用384模型跑完demo的后續(xù)流程(事實(shí)上,一直到部署結(jié)束,都沒能再成功下載過一個模型,想想當(dāng)時能成功下載384的模型,真的是幸運(yùn))。

          順利運(yùn)行demo推斷

          然后根據(jù)文檔,順利執(zhí)行了"Building an Engine"與"Running Inference"兩個步驟,運(yùn)行時間有些波動,最快大概再2.4ms一個,鑒于長度是384,與官方說的128長度2.2ms一個基本吻合了。這個時候的我,仿佛已經(jīng)完成了模型加速,幸福的表情難以言表。

          'additional_dict'模型中包含訓(xùn)練時的參數(shù)

          雖然說128長度的demo模型一直下不成功,但發(fā)現(xiàn)384的模型其實(shí)就是個checkout形式的tensorflow模型,所以就直接拿我們自己訓(xùn)練好的checkout模型來轉(zhuǎn)換。開始轉(zhuǎn)化模型:

          python?python/bert_builder.py?-m?/workspace/models/fine-tuned/bert_tf_v2_base_fp32_128_v2/model.ckpt-6001?-o?bert_base_128.engine?-b?1?-s?128?-c?/workspace/models/fine-tuned/bert_tf_v2_base_fp16_128_v2

          在短暫的等待之后,就迎來了ERROR!

          報錯表示,在模型數(shù)據(jù)加載過程中,出現(xiàn)了不支持的數(shù)據(jù)類型,于是在bert_builder.py的252/253行加入了代碼:

          print(pn)????#?打印參數(shù)名稱
          print(type(tensor))????#?打印參數(shù)類型

          再次運(yùn)行后發(fā)現(xiàn),一個叫"signal_early_stopping/STOP"的參數(shù)是布爾形式,這是在訓(xùn)練過程中用到的,所以將237行改為:

          param_names?=?[key?for?key?in?sorted(tensor_dict)?if?'early_stop'?not?in?key?and?'adam'?not?in?key?and?'global_step'?not?in?key?and?'pooler'?not?in?key]?

          'cls_squad_output_weights'模型中參數(shù)名稱不一致

          順利解決了上面的bug,再次運(yùn)行后,比上次多等待了一眨眼,就得到了一個全新的ERROR!

          報錯表示,參數(shù)中沒有一個叫"cls_squad_output_weights"的,demo是squad的一個樣例,而我的是二分類下游任務(wù),最后輸出層參數(shù)名稱不一致,根據(jù)上面打印的參數(shù)名字(不同的下游任務(wù)或者訓(xùn)練代碼,最后層的參數(shù)名字都可能不同),將217/218行代碼修改為:

          W_out?=?init_dict["output_weights"]
          B_out?=?init_dict["output_bias"]

          然后再次運(yùn)行,沒有報錯,進(jìn)入了相對較長的等待。當(dāng)"Saving Engine to bert_base_128.engine ?Done."出現(xiàn)的時候,這個時候的我,仿佛已經(jīng)完成了模型加速,幸福的表情難以言表。

          'ascii'中文讀取報錯

          趕緊以葫蘆畫瓢(將文檔與問題都用文件的形式提供),也運(yùn)行一次推斷:

          python?python/bert_inference.py?-e?bert_base_128.engine?-pf?"p.txt"?-qf?"q.txt"?-v?/workspace/models/fine-tuned/bert_tf_v2_base_fp32_128_v2/vocab.txt

          很快,就報了一個"ascii"編碼的錯誤(因?yàn)樽x取中文的緣故),在百度之后,執(zhí)行了下面一行得以解決(本容器中可使用C.UTF-8):

          export?LANG=C.UTF-8

          繼續(xù)運(yùn)行后,得到"Running inference in 437.362 Sentences/Sec"(2.286ms),后面還有一個squad相關(guān)的錯誤,直接被我忽略了。這個時候的我,仿佛已經(jīng)完成了模型加速,幸福的表情難以言表。

          模型結(jié)構(gòu)與demo不同

          后面我修改了bert_inference.py文件(根據(jù)自己需要,自行修改),打印出模型分類結(jié)果,發(fā)現(xiàn)結(jié)果是[128,2,1,1]維度的,并且沒有做最后的softmax操作,獲取第一行數(shù)據(jù)并softmax,然后發(fā)現(xiàn),結(jié)果是錯的,什么鬼,摔!
          這個錯誤讓我茶飯不思(那兩天吃得可好了),以為距離模型加速成功就一步之遙(其實(shí)還有好遠(yuǎn)),結(jié)果結(jié)果是錯的,根本不能用!對著代碼查這查那,用著google找這找那,絲毫沒有頭緒。一股神秘的力量,讓我回去看了tensorflow訓(xùn)練BERT下游任務(wù)的代碼,在我粗略的論文閱讀中,以及網(wǎng)絡(luò)/同事的介紹中,得到的信息都是,取BERT最后一層[CLS]的編碼直接進(jìn)行下游二分類訓(xùn)練(單層全連接+softmax)。但代碼中卻是,先經(jīng)過一層全連接+tanh,再接全連接+softmax。根據(jù)代碼得知,第一層的兩參數(shù)名叫"bert_pooler_dense_kernel","bert_pooler_dense_bias",所以將bert_build.py原237行修改為:

          param_names?=?[key?for?key?in?sorted(tensor_dict)?if?'early_stop'?not?in?key?and?'adam'?not?in?key?and?'global_step'?not?in?key]

          在tensorrt-api文檔【10】的幫助下,將bert_build.py中的squad_output函數(shù)修改為:

          def?squad_output(prefix,?config,?init_dict,?network,?input_tensor):
          ?????"""
          ?????Create?the?squad?output
          ?????"
          ""
          ??????
          ?????idims?=?input_tensor.shape
          ?????assert?len(idims)?==?5
          ?????B,?S,?hidden_size,?_,?_?=?idims
          ??????
          ?????p_w?=?init_dict["bert_pooler_dense_kernel"]
          ?????p_b?=?init_dict["bert_pooler_dense_bias"]
          ?????#這里其實(shí)可以直接取[CLS]的向量進(jìn)行后續(xù)運(yùn)算,但是沒能實(shí)現(xiàn)相關(guān)功能,就計算了所有的
          ?????pool_output?=?network.add_fully_connected(input_tensor,?hidden_size,?p_w,?p_b)
          ?????pool_data?=?pool_output.get_output(0)
          ?????tanh?=?network.add_activation(pool_data,?trt.tensorrt.ActivationType.TANH)
          ?????tanh_output?=?tanh.get_output(0)
          ??????
          ?????W_out?=?init_dict["output_weights"]
          ?????B_out?=?init_dict["output_bias"]
          ??????
          ?????W?=?network.add_constant((1,?hidden_size,?2),?W_out)
          ?????dense?=?network.add_fully_connected(tanh_output,?2,?W_out,?B_out)???????????????
          ?????set_layer_name(dense,?prefix,?"dense")
          ?????return?dense

          在相對較長的等待中,獲得了新的engine模型。在運(yùn)行了自己修改的推斷腳本后,得到了正確結(jié)果(使用了fp16,所以最后結(jié)果在萬分位上有所不同,但基本一致了)。這個時候的我,仿佛已經(jīng)完成了模型加速,幸福的表情難以言表。

          'nan'batch大小的配置問題

          為了對比下速度,多預(yù)測了幾個樣本,發(fā)現(xiàn)報錯,可能是因?yàn)闃?gòu)建engine的時候batch設(shè)置的是1,重新設(shè)置為20,再次運(yùn)行:

          python?python/bert_builder.py?-m?/workspace/models/fine-tuned/bert_tf_v2_base_fp32_128_v2/model.ckpt-6001?-o?bert_base_128.engine?-b?20?-s?128?-c?/workspace/models/fine-tuned/bert_tf_v2_base_fp16_128_v2

          得到新模型后,推斷多個樣本時,依然報錯,得到的都是nan結(jié)果。什么情況,這個batch size參數(shù)是擺設(shè)嗎!(后來我查看過5.1分支的代碼,配置有所不同,也許在5.1分支上,直接使用batch size是有作用的)天知道在經(jīng)過怎樣的過程之后,發(fā)現(xiàn)engine構(gòu)建過程中,有過配置設(shè)置:

          bs1_profile?=?builder.create_optimization_profile()
          set_profile_shape(bs1_profile,?1)
          builder_config.add_optimization_profile(bs1_profile)

          為了模型速度,構(gòu)建過程中只設(shè)置了batch size為1,8以及參數(shù)值這三個。在google一翻之后,一位大佬說,再讀取engine之后,設(shè)置使用第二個配置(就是以傳入?yún)?shù)為batch size的配置)就可以了,也就是添加一行代碼"context.active_optimization_profile = 1",很有道理,一運(yùn)行發(fā)現(xiàn),"out of index"!還是要暴力處理,后來直接注釋了其他兩個配置,終于運(yùn)行成功了,batch size在[1,20] 之間都得到了正確結(jié)果。這個時候的我,仿佛已經(jīng)完成了模型加速,幸福的表情難以言表。

          tensorflow與tensorRT的推斷時間對比

          然后就得到了一開始的那張時間對比表,tensorflow是1.14版,float32精度,使用estimator進(jìn)行預(yù)測,tensorrt是6.0版,直接使用python調(diào)用:

          max_seqbatch_size15102040100
          128Tensorflow(ms)20244576130300
          128tensorRT(ms)2.25.27.210.11951

          tensorRT server for BERT

          'segmentation'cuda與flask的沖突

          python調(diào)用成功后,就簡單把bert_inference.py程序改成了一個python服務(wù)程序,順利啟動服務(wù)之后,調(diào)用服務(wù)接口,驚喜來了:

          一個光禿禿的提示(報錯位置都沒有),反正沒得結(jié)果。后來一查百度,說這個多為內(nèi)存不當(dāng)操作造成,這讓我一個半路出家的程序員怎么辦!后來仔細(xì)排查了報錯位置,發(fā)現(xiàn)是cuda報出的錯,結(jié)合這個信息,在面向google編程之后,得知pycuda上下文與http上下文有一些沖突(超過我知識范圍了),在初始化cuda的時候不能使用autoinit,得調(diào)用一次init一次,

          #import?pycuda.autoinit?#注釋掉自動初始化
          #?初始化cuda
          cuda.init()
          device?=?cuda.Device(0)
          ctx?=?device.make_context()

          #?中間所有處理程序

          #?結(jié)束上下文
          ctx.pop()

          如上所示,每次調(diào)用的時候都得先初始化,經(jīng)過這樣的修改以后,果然跑通了。但耗時了3000ms一個樣本,時間足足多了上百倍,還能不能好好地玩耍了。這還不是最關(guān)鍵的,最關(guān)鍵的是,所有的返回結(jié)果全部變成了[0.5,0.5],好吧在服務(wù)中用python直接調(diào)用模型是行不通了(并不是真正的行不通,只是我這個渣渣,cuda也不懂,解決不了這兩個問題)。

          tensorrt模型文件的確認(rèn)

          這個時候,只能去使用tensorrt server【11】了。根據(jù)【11】文檔里所說,只要求一個配置文件和模型文件,就可以啟動相應(yīng)的docker服務(wù)了。但發(fā)現(xiàn)這個server能識別的tensorrt模型文件是一個以.plan結(jié)尾的文件,但我只有一個以.engine結(jié)尾的模型文件。后面我查閱了百度/gooogle相關(guān)文件,都沒找到如何將engine轉(zhuǎn)為plan文件,后來只找到一個在tensorrt6.0已經(jīng)被棄用的方法"write_engine_to_file()",但這不能用,而且也不知道寫進(jìn)去的文件是啥類型。后來我搜索了【5】中所有的"plan"字符,終于找到一句話:

          Write out the inference engine in a serialized format. This is also called a plan file.

          這句話的意思應(yīng)該就是說,engine跟plan是一個東東(后面確實(shí)讀取成功了,應(yīng)該是一個東西,當(dāng)時還是有猜的成分)。

          'deserialize'tensorrtserver版本問題

          按照【11】中所講,我認(rèn)為下載官方提供的docker來部署最為方便,最主要的是,我發(fā)現(xiàn)服務(wù)器上已經(jīng)有一個tensorrt server的鏡像了,應(yīng)該是同事之前下的,下鏡像的過程都省掉了。根據(jù)【11】中Model相關(guān)內(nèi)容,將模型文件重命名為model.plan,將配置文件修改為(有問題,后面要改):

          name:?"bert"
          platform:?"tensorrt_plan"
          max_batch_size:?20
          input?[
          ????{??
          ??????name:?"input0"
          ??????data_type:?TYPE_INT32
          ??????dims:?[128]
          ????},?
          ????{??
          ??????name:?"input1"
          ??????data_type:?TYPE_INT32
          ??????dims:?[128]
          ????},?
          ????{??
          ??????name:?"input2"
          ??????data_type:?TYPE_INT32
          ??????dims:?[128]
          ?????}??
          ]??????
          output?[
          ????{??
          ??????name:?"output0"
          ??????data_type:?TYPE_FP16
          ???dims:[128,2]?????????????????????????????????????????????????????????????????????????????????????????????????????????
          ????}??
          ]?

          根據(jù)【11】中的命令,直接運(yùn)行:

          NV_GPU=1?nvidia-docker?run?--rm?--shm-size=1g?--ulimit?memlock=-1?--ulimit?stack=67108864?-p50014:8000?-p50015:8001?-p50016:8002?-v?/自己的路徑/models:/models?nvcr.io/nvidia/tensorrtserver:19.08-py3?trtserver?--model-repository=/models

          直接一個報錯"trtserver: unrecognized option '--model-repository=/models'",根據(jù)提示,將參數(shù)名"--model-repository"改為了"--model-store",然后再運(yùn)行,就得到了又一個錯誤:

          在一個不知道在哪里的文件,報了一個c++的錯誤,一籌莫展。根據(jù)提示,好像是batch size的問題,也可能是engine文件并不是plan文件導(dǎo)致讀錯了,也可能是版本問題(tensorrt server跟tensorrt的版本不統(tǒng)一【12】)。針對前面兩種情況,試了各種姿勢,依然是報這個錯,沒辦法,只能重新下載個docker鏡像了。

          docker?pull?nvcr.io/nvidia/tensorrtserver:19.09-py3

          當(dāng)然下載不會一帆風(fēng)順的,會有權(quán)限錯誤提示,在【11】中也多次提到,下載docker容器得先有NGC 權(quán)限【13】。

          'CustomEmbLayerNormPluginDynamic'插件缺失

          兩個小時之后,下載完畢,然后運(yùn)行:

          NV_GPU=1?nvidia-docker?run?--rm?--shm-size=1g?--ulimit?memlock=-1?--ulimit?stack=67108864?-p50014:8000?-p50015:8001?-p50016:8002?-v?/自己的路徑/models:/models?nvcr.io/nvidia/tensorrtserver:19.09-py3?trtserver?--model-repository=/models

          大概等了2秒鐘,有點(diǎn)開心,已經(jīng)過了上個bug出現(xiàn)的時間,又過了1秒,果然來了個新bug:

          讀取"CustomEmbLayerNormPluginDynamic"插件錯誤,這個插件有點(diǎn)眼熟,在bert_build.py文件里面出現(xiàn)過,在咨詢了一波google之后,發(fā)現(xiàn)一個類似的問題【14】,在根據(jù)bert_build.py文件,將libbert_plugins.so/libcommon.so(在【9】中build文件夾中,編譯之后的)文件拷進(jìn)docker容器里。進(jìn)入容器:

          NV_GPU=1?nvidia-docker?run?-it?--shm-size=1g?--ulimit?memlock=-1?--ulimit?stack=67108864?-p50014:8000?-p50015:8001?-p50016:8002?-v?/自己的路徑/models:/models?nvcr.io/nvidia/tensorrtserver:19.09-py3?/bin/bash

          然后運(yùn)行:

          export?LD_PRELOAD=/opt/tensorrtserver/libbert_plugins.so:/opt/tensorrtserver/libcommon.so

          so文件位置是自己確定的,然后運(yùn)行:

          trtserver?--model-repository=/models

          config.pbtxt配置文件不對

          這次運(yùn)行時間更長了,好開心,然后:

          根據(jù)這個提示,是配置文件有問題,修改后又報錯再修改再報錯,這樣循環(huán)幾次后,配置文件變成了:

          name:?"bert"
          platform:?"tensorrt_plan"
          max_batch_size:?20
          input?[
          ????{
          ??????name:?"input_ids"
          ??????data_type:?TYPE_INT32
          ??????dims:?[128]
          ????},
          ????{
          ??????name:?"segment_ids"
          ??????data_type:?TYPE_INT32
          ??????dims:?[128]
          ????},
          ????{
          ??????name:?"input_mask"
          ??????data_type:?TYPE_INT32
          ??????dims:?[128]
          ????}
          ]
          output?[
          ????{
          ??????name:?"cls_dense"
          ??????data_type:?TYPE_FP32
          ??????dims:?[128,?2,?1,?1]
          ????}
          ]

          再次運(yùn)行之后,一直沒報錯,好像成功了,根據(jù)【11】中狀態(tài)檢查,運(yùn)行了下:

          curl?localhost:50014/api/status

          然后得到了:

          哦耶,好像加載成功了,這個時候的我,仿佛已經(jīng)完成了模型加速,幸福的表情難以言表。

          Client

          tensorrtserver.api下載安裝

          看似tensorrt的服務(wù)已經(jīng)成功部署了,現(xiàn)在就需要在我自己的服務(wù)內(nèi)部調(diào)用成功了。根據(jù)【11】當(dāng)中關(guān)于client的介紹,client的環(huán)境可以自己打鏡像/編譯/下載鏡像/下載編譯好的結(jié)果,琢磨著下載編譯好的結(jié)果最簡單了,所以在【15】中找到了自己需要的版本,直接運(yùn)行:

          wget?https://github.com/NVIDIA/tensorrt-inference-server/releases/download/v1.6.0/v1.6.0_ubuntu1804.clients.tar.gz
          tar?-zxvf?v1.6.0_ubuntu1804.clients.tar.gz

          然后安裝一下:

          cd?python
          pip?install?tensorrtserver-1.6.0-py2.py3-none-linux_x86_64.whl

          'dimension'batch大小的配置問題

          有了依賴環(huán)境之后,根據(jù)【11】中的python api,成功地將模型調(diào)用添加到我的服務(wù)中去,最后調(diào)用測試,這個時候的我,仿佛已經(jīng)完成了模型加速,幸福的表情難以言:

          根據(jù)報錯提示,是batch size不對,將樣本數(shù)量換成20后,果然運(yùn)行正確了。為什么直接用python調(diào)用模型的時候,樣本數(shù)只要小于batch size就可以了!后來我將bert_build.py文件的"set_profile_shape"函數(shù)改為了:

          def?set_profile_shape(profile,?batch_size):
          ????maxshape?=?(batch_size,?S)
          ????minshape?=?(1,?S)
          ????optshape?=?(batch_size,?S)?#?這個batch的大小在最大和最小之間就可以,可以相等
          ????profile.set_shape("input_ids",?min=shape,?opt=shape,?max=shape)
          ????profile.set_shape("segment_ids",?min=shape,?opt=shape,?max=shape)
          ????profile.set_shape("input_mask",?min=shape,?opt=shape,?max=shape)

          其中"set_shape"等函數(shù)的含義可以在文檔【10】中找到,修改后,又將全流程走了一遍,構(gòu)建engine,部署tensorrt server,運(yùn)行client,然后我真的完成了了模型加速,幸福的表情一言難盡!最后測試20個樣本調(diào)用服務(wù)的時間是15ms左右,比python直接調(diào)用延遲了5ms左右。

          上線

          Serialization Error

          果然,我還是笑得太早,太年輕了。剛把服務(wù)推到測試上,就來了驚喜:

          一看錯誤,模型加載錯誤,什么情況,我不是已經(jīng)跑通了嗎?經(jīng)過一系列查詢之后,發(fā)現(xiàn)tensorrt在不同GPU(主要根據(jù)計算能力分類)上編譯的模型是不能通用的,我之前在調(diào)研機(jī)上跑的,GPU型號是V100(計算能力7.0),而測試機(jī)上是P4(計算能力6.1),在V100上編譯的模型不能再P4使用,根據(jù)github上前輩提示,在CMakeLists.txt文件的第21行添加:

          -gencode?arch=compute_60,code=sm_60?\

          這樣就可以在P4上進(jìn)行編譯了,后來驗(yàn)證P4上的模型可以在P100的機(jī)器上跑通。當(dāng)然編譯的過程顯然不能一帆風(fēng)順,中間出現(xiàn)了out of memory的問題,后來測試發(fā)現(xiàn),大概需要5800M的顯存才能編譯成功。線上的GPU是P100的,順利運(yùn)行了新編譯的模型,心里終于微微一笑;bert在V100上的運(yùn)行速度大概是P100的5倍,而且nvidia主要在T4跟V100上優(yōu)化bert推斷的,而且模型轉(zhuǎn)換時P100上不能使用float16精度模式(只能用float32),所以新編譯的模型效率提高有限;想到新編譯的模型比tensorflow的效率只提高了30%左右,感覺之前的努力突然不香了。

          總結(jié)

          壓力/需求使人進(jìn)步,如果沒有"time out"報錯,我在部署完gpu版的BERT模型就結(jié)束了,這不,硬著頭皮也要上,從完全沒有聽過tensorrt到成功部署bert,大概用了兩周多時間。雖然現(xiàn)在對tensorrt依然只是了解皮毛,對cuda編程更是兩眼一抹黑,但沒關(guān)系,有了這個開端,后面慢慢學(xué)。
          在部署過程中,百度/google/知乎各種找教程,都沒有找到部署B(yǎng)ERT的詳細(xì)過程,也為了提升自身,寫下自己遇到的坑,以及部分解決辦法,供大家一起交流進(jìn)步。

          參考(閱讀原文可查看鏈接)

          【1】《從零開始學(xué)習(xí)自然語言處理(NLP)》-BERT推理加速實(shí)踐(6)
          【2】《從零開始學(xué)習(xí)自然語言處理(NLP)》-BERT模型推理加速總結(jié)(5)
          【3】加速 BERT 模型有多少種方法?從架構(gòu)優(yōu)化、模型壓縮到模型蒸餾,最新進(jìn)展詳解!
          【4】NVIDIA發(fā)布TensorRT 6,突破BERT-Large推理10毫秒大關(guān)
          【5】What Is TensorRT?
          【6】tensorRT的debian方式安裝
          【7】使用python將tensorflow模型轉(zhuǎn)為tensorRT模型
          【8】Real-Time Natural Language Understanding with BERT Using TensorRT
          【9】tensorRT6.0分支BERT官方demo
          【10】tensorrt-api
          【11】NVIDIA TensorRT Inference Server
          【12】TensorRT inference server documentation versions
          【13】NGC guide
          【14】CustomEmbLayerNormPluginDynamic插件加載問題
          【15】tensorrt-inference-server/releases
          【16】DeepLearningExamples

          瀏覽 84
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕92页 | 久久精品视频电影 | 欧美第8页 | 成人网4438 | 色吧AV|