首頁>技術>

作者 | AI實戰派

AI實戰派

和你一起看看AI真實落地的樣子

當我們千辛萬苦完成了前面的資料獲取、資料清洗、模型訓練、模型評估等等步驟之後,終於等到老大說“上線”啦。想到辛苦訓練出來的模型要被呼叫還有點小激動呢,可是真當下手的時候就有點懵了:模型要怎麼部署?部署在哪裡?有什麼限制或要求?

本文基於以上常見的部署困惑,介紹一下深度學習中TensorFlow(Keras)模型部署時需要考慮的問題以及常用部署方法,並通過實際的模型部署來進行方案比較。

01

問題分析

筆者較為推薦的思考路徑是從問題和限制出發,思考好了這些限制條件之後再去搜索對應的解決方案,這樣就可以避免限於方案過多挑不過來的窘境,並且若是挑不到完美的方案,還可以根據條件對現有方案進行改造。

現在就來看看部署模型我們通常需要考慮什麼問題。

首先是模型的使用場景,根據使用場景就可以獲取到對應的效能等要求。舉個例子來說,如果是要上線給使用者使用的,哦吼,這塊最起碼速度要求就很高,畢竟使用者可不像自己人,沒有多少耐心一直等你的載入圈轉呀轉,具體的指標根據場景和應用而定,不過一般會在數毫秒 最多可以到數十毫秒每條的樣子。

此外,如果是基於網路呼叫那還好說,機器在自己手上,土豪就可以各顯神通了,如果是離線的手機APP,那就還有大小的要求,畢竟動不動讓你下個幾百M的app看著也煩呀。

接下來,如果是基於網路呼叫的,還要看看自己手裡的資源夠不夠,是壕到有專門的GPU用於部署呢,還是隻能苦逼地使用CPU呢,如果是GPU部署,那可以偷笑了,GPU部署服務方便的同時效能又好,畢竟各種各樣的優化都是苦於資源不夠,對於大夥兒來說可以躺賺誰願意坐著賺錢啊。

好吧,CPU就CPU,然而CPU伺服器裡頭也是可以區別的,是選擇有裝好例如Python、TensorFlow等環境的呢,還是赤條條的要麼自己裝要麼另尋出路的。

02

方案介紹

接下來,本文會根據幾種常見的限制組合來列出對應的解決方案,需要部署到手機端的話TensorFlow已經給出了TensorFlow Lite的解決方案,筆者暫未接觸到手機部署相關的需求,就不深入介紹了。接下來就以最常見的服務提供方部署模型,通過網路呼叫方式通訊介紹兩套方案。

基於預測改造的方案

模型在測試集上進行測試知道吧?讀取檔案後呼叫模型對每條case進行預測,最後將所有預測結果和正確答案對比,計算出各種指標。整個流程如下圖:

而在提供服務時,輸入是由外部傳入的,因此不需要前面的讀取檔案操作,最後提供預測結果即可,也不需要最後的對比、計算指標的步驟。為了處理接收外部輸入、返回預測結果,並做一些業務邏輯相關的處理,需要引入一個處理中心,這個處理中心通常是web框架 如 flask、tornado、Django等,其作用是搭建http服務,將外部輸入傳給模型,將模型預測結果返回。流程如下圖:

再來梳理一下流程,在同一臺機器上通過web框架如flask等搭建好對外服務,初始化時載入好模型。當外部應用服務例如搜尋應用的輸入到來時,例如傳來一句話,或者上傳了一張圖片,對外服務就將輸入傳給預處理函式,將輸入處理成可以給模型預測的樣子,例如做標準化、去噪等等,隨後模型進行預測,並將結果返回給對外服務,服務將結果包裝一下返回給搜尋應用回去。

一個搜尋應用會有很多個模型和子模組構成,那麼對於每個模型都需要有一個對外服務來對模型進行封裝並提供通訊介面。

整個過程並沒有多少難點,搭建http服務使用簡單的demo即可,然後將預測函式改造改造就可以啦,最終的效能視乎部署的裝置及模型深度而定。

基於TF-Serving的方案

如果在要部署的伺服器上不願或無法裝和訓練一樣的環境,也可以使用TensorFlow推出的Serving工具,此處對小白來說更推薦基於docker的安裝方式,只需要安好對應映象即可,否則得自己編譯安裝。基於docker安裝的話需要提前想好是用cpu版本還是gpu版,根據版本拉取對應的映象。

那這個TF-Serving是什麼樣的呢?先來看看基於TF-Serving後最終整個流程是怎麼工作的:

如圖,在TF-Serving流程上一般會用到兩臺機器(或更多),其中一臺作為TF-Serving的伺服器,專門給模型用來部署並預測,應用服務放在另外的伺服器,跟其他服務共享環境。

我們將模型部署在TF-Serving的伺服器上,TF-Serving會自動根據傳入的埠和模型路徑進行部署,模型所在的伺服器不需要python環境(以python訓練為例),隨後應用服務直接對模型所在伺服器發起服務呼叫,呼叫可以通過java或python的grpc進行呼叫,具體呼叫方式參考當前使用版本的手冊。

不過TF-Serving一個很大的坑在於:資料預處理的部分需要交給應用服務做,TF-Serving只接收張量輸入,如文字分類的模型,它就只接收序列的id,而非句子本身,並且輸出返回的是id而非文字化的標籤,因此也需要額外一層轉換。

然後來看看怎麼將模型部署到TF-Serving上:

流程比較簡單,首先在GPU伺服器上訓練好模型後,將模型儲存好,再根據網上的轉換指令碼轉換成TF-Serving接受的格式,不論使用Tensorflow還是Keras都不影響(pytorch麻煩出門右轉),只是儲存的函式不同而已,查好具體用哪個函式即可,最後將生成出來的檔案上傳到安裝了TF-Serving的伺服器,啟動服務即可。

03

方案對比

接下來本文先以一個實際的BERT-base+Fasttext文字二分類模型為例子,分別用以上兩個方案用GPU和CPU進行部署,看看他們效能之間的差異,最後在總結一下不同方案的適用場景和差異。

部署效能對比

GPU 基於 模型預測改造方案

首先上GPU:

Tesla V100 訓練起來很給力,那麼預測起來時間怎麼樣呢?筆者以1500個句子作為輸入,在伺服器上搭建好http服務後遠端呼叫,最終平均時間是0.0102s/條,10毫秒每條,對於大多數線上使用來說算是還可以了,畢竟BERT的體積之大和推理之慢但效果之好是大家有目共睹的。

CPU 基於 模型預測改造方案

那麼把這個模型移到CPU上又會怎麼樣呢?在Intel(R) Xeon(R) Gold 61xx CPU 2*32 上採用同樣的改造和服務搭建方式,同樣的1.5k句子跑起來,最終平均時間是0.390s/條。

看到這個結果,筆者一開始瞪大了眼睛,仔細確認了好幾遍數量級,最終無可奈何的接受了這個現實,390ms/條的速度,拿給內部自己人呼叫都要嫌慢吧。然後回頭去某東上搜了下V100,好吧。。人家快是有道理的。

CPU 基於 TF-Serving 方案

那TensorFlow官方強推的Serving工具表現怎麼樣呢?或許經過推理優化之後執行速度或許會快一些吧?實驗結果也證實了這個假設,cpu版本的TF-Serving平均耗時為0.292 s/條, 比直接呼叫足足快了100ms,看來強推還是有道理的。

部署優化

雖然知道業界對BERT推理過慢廣泛詬病,但在GPU和CPU下差距如此之大還是有些出乎意料。吃驚歸吃驚,還得看看有沒有優化的方法。如果我們把CPU下耗時極大的BERT放到GPU會怎麼樣?將原始的BERT作為服務放到GPU上,這樣平時訓練和線上預測取embedding都從這裡取,這樣我們只需要部署接在BERT後面的小模型即可,哪怕是用CPU也扛得住吧?雖然會犧牲微調BERT帶來的提升,但是畢竟可以上線呀,比因效能太差而放棄要好多了。

在GPU上部署BERT服務,這裡就要用到筆者非常喜歡的 bert-as-service了,它是python的一個bert庫,能夠讓bert作為服務,接收句子輸入返回bert編碼的句子向量。

部署之後測試一下效能,不使用batch的單條預測下平均耗時是0.0073s/條,7ms,可以接受。那分離開來的fasttext模型呢?部署在CPU的TF-Serving後平均耗時是0.0028s/條,3ms,也可以接受,總耗時竟然跟整個模型放在GPU上是一樣的,瓶頸果然還是在BERT呀。

這套方案同樣可以遷移到其他場景,例如將使用者的各種資訊訓練好Embedding後作為公共資源由模型各自呼叫,或者可以將耗記憶體較大的word2vec embedding檔案放到有較多記憶體的機器上,再通過網路進行資料傳輸。

04

方案總結

現在來總結一下上邊的實驗,先看一下以上三種方案的流程圖(每個黑色框代表一臺機器):

然後來看一下方案分別的耗時:

首先要說的是,能上GPU一定要上GPU!鈔能力節省非常多的時間和精力。然後我們挨個方案來說說優缺點。

好處:修改簡單易於上手。

壞處:

推理效能為三種方案之內最慢的。推理伺服器需要有python環境。

第二套方案利用TF-Serving進行部署,TF-Serving自動會進行部署和埠監聽。

好處:

速度較方案一快。不需要python環境。

壞處:

安裝較麻煩,最好使用docker。輸入輸出都需要轉換和處理。

第三套方案是在方案二上的優化,將耗費資源較多的部分放到效能較好的機器上,可以作為公共資源給多個小網路共同使用。

好處(其他同方案二):

速度最快。

壞處(其他同方案二):

需要有效能好的機器存放耗資源的網路,這塊需要協調。多一次網路通訊,需要承受網路波動的影響,如果TF-Serving和GPU機器屬於不同網路環境則更為麻煩,需要藉助VPN等手段。每個對外服務呼叫模型需要配置專門的邏輯:從GPU伺服器取Embedding,作為輸入給TF-Serving,才能得到TF-Serving的輸出。

縱觀所有方案,發現其實我們可以做一些小融合,以方案三(或方案二)為基礎,結合方案一的包裝,來去除TF-Serving輸入輸出需要轉換,以及方案三中每個服務需要配置專門邏輯的缺點,流程如下圖:

以方案三為例,在TF-Serving的伺服器上再增加一層中介,主要做輸入輸出的轉換,再承擔中轉的作用。

當外部輸入到來時,對外服務接收請求,處理後傳給GPU機器,得到embedding,而後將embedding傳給TF-Serving的模型,得到預測結果後轉換成外部需要的格式,最後打包結果返回給其他服務。

這樣,方案四既擁有了方案三速度最快的優點,也避免了TF-Serving需要做輸出輸出轉換,以及在TF-Serving與GPU Embedding伺服器中來回跑的缺點。

05

最後

本文列舉了基於網路呼叫的幾個模型部署的方案,並且根據實際場景進行優化和變型,如果要在此之上要追求極致的效能,就只能自己動手豐衣足食了,例如用C++或Go重寫推理部分,或者利用大公司自研的框架進行部署和推理。

The End

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 當中國詩詞大會邂逅了Flutter,從此我的眼裡只有你