9n-triton部署bert模型實戰經驗

一、背景

對於算法工程師來說,通常採用python語言來作爲工作語言,但是直接用python部署線上服務性能很差。這個問題困擾了我很久,爲了緩解深度學習模型工程落地性能問題,探索了Nvidia提供的triton部署框架,並在九數中臺上完成線上部署,發現性能提升近337%!!原服務單次訪問模型推理時間175ms左右,同模型框架單次訪問推理時間縮減至40ms左右)。本文僅以本次部署服務經驗分享給諸多受制於python性能問題的夥伴,希望有所幫助。

二、問題發現

組內原算法服務一直採用python-backend的鏡像部署方式,將算法模型包裝成接口形式,再通過Flask外露,打入docker中啓動服務,但是發現推到線上接口響應時間過長,非常影響用戶體驗,於是想做出改進。python後端部署一般存在以下問題:

1. 性能問題:
由於python是一種解釋語言,因此對比於其他編譯語言(如C,C++或go)要慢很多,這對於要求高性能或者低延遲快速響應的線上服務很不友好,用戶體驗很差。
GIL全局鎖限制,多線程困難,限制了高併發能力,限制程序性能。
python內存佔用過多,資源浪費。
2. 部署複雜:
自訓練/自搭建算法模型往往需要一系列的相關依賴和系統庫,如果利用python環境直接部署至線上,則必須解決將所有依賴庫同步打包至對應容器中,並很可能需要額外解決不同庫版本衝突問題,十分麻煩。

爲了解決上述困擾,我們經過調研行業內其他實踐經驗,決定摒棄傳統鏡像部署方式,擺脫python部署環境,換用triton部署算法模型。

三、部署實例

本試驗通過fine-tune的Bert模型進行文本分類任務,並通過九數算法中臺包裝的triton部署框架部署至公網可訪問,以下介紹了我們團隊部署的全流程和途中踩到的坑,以供大家快速入手(以下均以Bert模型爲例):

step 1: 將訓練好的模型保存爲onnx或torchscript(即.pt)文件格式。據調研行業經驗,onnx一般用於cpu環境下推理任務效果較好,.pt文件在gpu環境下推理效果較好,我們最終選擇了將模型轉化爲.pt文件。代碼例子如下:

import torch
from transformers import BertTokenizer, BertForSequenceClassification

tokenizer = BertTokenizer.from_pretrained('./pretrained-weights/bert-base-chinese')
model = BertForSequenceClassification.from_pretrained('./pretrained-weights/bert-base-chinese', num_labels=10)
# Trace the wrapped model
# input_ids和attention_mask來自tokenizer, 具體可看一下torch.jit.trace用法
traced_model = torch.jit.trace(model, (input_ids, attention_mask))
traced_model.save("./saved_model_torchscript_v3.pt")

本段代碼借用了torch.jit.trace的存儲方式,輸入是文本經過tokenizer之後的input_ids和attention_mask,輸出是未經softmax處理的線性層。我們嘗試將softmax部分包裝進模型中一起打包成pt文件,使模型能夠直接吐出分類類別,方案是外層再包裝一層forward,代碼例子如下:

class BertSequenceClassifierWrapper(torch.nn.Module):
    def __init__(self, model):
        super().__init__()
        self.model = model.cuda()

    def forward(self, input_ids, attention_mask):
        outputs = self.model(input_ids=input_ids.cuda(), attention_mask=attention_mask.cuda())
        # Apply softmax to the logits
         probs = softmax(outputs.logits, dim=-1)
        # Get the predicted class
         predicted_class = torch.argmax(probs, dim=-1)
        return predicted_class

wrapped_model = BertSequenceClassifierWrapper(model)
traced_model = torch.jit.trace(wrapped_model, (input_ids, attention_mask))
traced_model.save("./saved_model_torchscript_v3.pt")

然而,參考於行業內實踐,我們沒有選擇將tokenizer部分包裝至模型內部,這是因爲torchscript僅接受數組類型輸入而非文本。最終,我們封裝的模型輸入爲input_ids和attention_mask,輸出爲分類結果(標量輸出)。

【注】:坑點:

轉onnx需要額外安裝transformers-onnx包,需要sudo權限,九數上不能執行,建議本地轉換。
對於.pt類型文件,當前九數triton部署僅支持gpu方式推理方式,不支持cpu推理,且torch版本有強要求限制 torch ==1.10.0,cuda11.2(更高版本似乎也可),故我們在保存時必須要在torch ==1.10.0,cuda11.2環境下生成pt文件,不然會部署失敗。
轉pt文件時建議使用torch.jit.trace而非torch.jit.script,後者經常出現引擎不兼容問題。

step 2: 將.pt文件存放在九數磁盤目錄下指定位置,注意,目錄格式需要嚴格按照要求,具體可參考九數幫助文檔。

目錄格式如下(其中model.pt即爲我們訓練好的模型):

pytorch-backend-online
|-- pytorch-model
|   |-- 1
|   |   |-- model.pt
|   `-- config.pbtxt

config.pbtxt配置如下:

name: "pytorch-model"
platform: "pytorch_libtorch"

input [
  {
    name: "INPUT__0"
    data_type: TYPE_INT64
    dims: [1, 512]
  },
  {
    name: "INPUT__1"
    data_type: TYPE_INT64
    dims: [1, 512]
  }
]
output [
  {
    name: "OUTPUT__0"
    data_type: TYPE_INT64
    dims: [1, 1] 
  }
]
instance_group [
  {
      count: 1
  }
]

配置中,我們需要指定輸入和輸出的維度以及數據類型。注意,數據類型指的是每個可迭代對象的類型(比如512維向量每個維度都是int64)。在本實例中,我們定義了兩個輸入均爲1*512維向量,輸出爲一個標量。

step 3: 模型註冊。需要到九數上註冊你的模型,然後才能部署,方式如下:





 

模型註冊表填寫如下:





 

坑點:圖中step2定義的一級目錄,比如 /home/{erp}/xxx/xxx/xxx。

step 4: 模型註冊好之後,就可以在註冊好的模型下點擊:部署-測試





 

然後需要填寫UI界面的信息。





 

到這裏,如果模型沒有問題,部署就是成功了~

step 5: 測試端口通不通。如果是測試環境,我們可以通過post接口在notebook中測試接口通不通,測試demo如下:





 

URL來自獲取方式如下:





 

如果測試沒有問題,就可以轉生產了~配置好域名和端口就可以公網訪問了。至此,triton框架部署torchscript方式完結。

四、結語

本文主要展示了一個基於Bert模型finetune的結果部署,經我們線下測試,對比於原有onnx在cpu機器上的推理速度增幅超過300%。
本項工作由殷擎,孫研同學共同完成,致謝團隊工作者!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章