日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

开源项目 | 五分钟搭建BERT服务,实现1000+QPS

發布時間:2024/10/8 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 开源项目 | 五分钟搭建BERT服务,实现1000+QPS 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


作者丨劉欣

單位丨香儂科技算法架構負責人

研究方向丨NLP工程化、算法平臺架構


深度學習模型在訓練和測試時,通常使用小批量(mini-batch)的方式將樣本組裝在一起,這樣能充分利用 GPU 的并行計算特性,加快運算速度。?


但在將使用了深度學習模型的服務部署上線時,由于用戶請求通常是離散和單次的,若采取傳統的循環服務器或多線程服務器,在短時間內有大量請求時,會造成 GPU 計算資源閑置,用戶等待時間線性變長。?


基于此,我們開發了 service-streamer,它是一個中間件,將服務請求排隊組成一個完整的 batch,再送進 GPU 運算。這樣可以犧牲最小的時延(默認最大 0.1s),提升整體性能,極大優化 GPU 利用率。


Github開源鏈接:


https://github.com/ShannonAI/service-streamer


功能特色



安裝步驟


可通過 pip 安裝,要求 Python>=3.5:


pip?installservice_streamer

五分鐘搭建BERT服務


為了演示 API 使用方法,service-streamer 提供了一個完整的教程和示例代碼。如何在五分鐘搭建起基于 BERT 模型的完形填空服務,每秒處理 1000+ 請求。點擊文章左下角“閱讀原文”查看完整代碼。
1. 首先我們定義一個完型填空模型(bert_model.py),其 predict 方法接受批量的句子,并給出每個句子中 [MASK] 位置的預測結果。


class?TextInfillingModel(object);???????...batch=["twinkle?twinkle?[MASK]?star",????????????"Happy?birthday?to?[MASK]",????????????'the?answer?to?life,?the?[MASK],?and?everything']model=TextaInfillingModel()outputs=model.predict(batch)print(outputs)#['little',?'you',?'universe'?]
2. 然后使用 Flask 將模型封裝成 web 服務 flask_example.py。這時候你的 web 服務每秒鐘只能完成 12 句請求。
model=TextInfillingModel()@app.route("/naive",?methods=["POST"])def?naive_predict(?):??????inputs?=?request.form.getlist("s")??????outputs?=?model.predict(inputs)??????return?jsonify(outputs)app.run(port=5005)@app.route("/naive",?methods=["POST"])
def?naive_predict(?):
??????inputs?=?request.form.getlist("s")
??????outputs?=?model.predict(inputs)
??????return?jsonify(outputs)

app.run(port=5005)
3. 下面我們通過 service_streamer 封裝你的模型函數,三行代碼使 BERT 服務的預測速度達到每秒 200+ 句(16 倍 QPS)。
from?service_streamer?import?ThreadStreamer?streamer=?ThreadedStreamer?(model.predict,batch_size=64,?max_latency=0.1)@app.route("/stream",?methods=["POST"])def?stream_predict(?):?????inputs?=?request.form.getlist("s")????outputs?=?streamer.predict(inputs)????return?isonify(outputs)app.run(port=5005,?debug=False)import?ThreadStreamer?streamer=?ThreadedStreamer?(model.predict,batch_size=64,?max_latency=0.1)

@app.route("/stream",?methods=["POST"])
def?stream_predict(?):
?????inputs?=?request.form.getlist("s")
????outputs?=?streamer.predict(inputs)
????return?isonify(outputs)

app.run(port=5005,?debug=False)


4. 最后,我們利用 Streamer 封裝模型,啟動多個 GPU worker,充分利用多卡性能實現每秒 1000+ 句(80 倍 QPS)。
import?multiprocessingfrom?service_streamer?import?ManagedModel,?Streamermultiprocessing.set_start_method("spawn",?force=True)class?ManagedBertModel(ManagedModel):?????def?init_model(self):???????????self.model?=?TextInfillingModel(?)??????def?predict(self,?batch):????????????return?self.model.predict(batch)streamer?=Streamer(ManagedBertModel,?batch_size=64,?max_latency=0.1,?worker_num?=?8,?cuda_devices=(0,1,2,3))app.run(port=5005,?debug=False)
from?service_streamer?import?ManagedModel,?Streamer
multiprocessing.set_start_method("spawn",?force=True)

class?ManagedBertModel(ManagedModel):

?????def?init_model(self):
???????????self.model?=?TextInfillingModel(?)

??????def?predict(self,?batch):
????????????return?self.model.predict(batch)

streamer?=Streamer(ManagedBertModel,?batch_size=64,?max_latency=0.1,?
worker_num?=?8,?cuda_devices=(0,1,2,3))

app.run(port=5005,?debug=False)


運行 flask_multigpu_example.py 這樣即可啟動 8 個 GPU worker,平均分配在 4 張卡上。

更多指南


除了上面的 5 分鐘教程,service-streamer 還提供了:?



API介紹


快速入門
通常深度學習的 inference 按 batch 輸入會比較快。
outputs?=?model.predict(batch_inputs)


用 service_streamer 中間件封裝 predict 函數,將 request 排隊成一個完整的 batch,再送進 GPU。犧牲一定的時延(默認最大 0.1s),提升整體性能,極大提高 GPU 利用率。
from?service_streamer?import?ThreadedStreamer#?用Streamer封裝batch_predict函數streamer?=?ThreadedStreamer(model.predict,?batch_size=64,?max_latency=0.1)#?用Streamer異步調用predict函數outputs?=?streamer.predict(batch_inouts)import?ThreadedStreamer

#?用Streamer封裝batch_predict函數
streamer?=?ThreadedStreamer(model.predict,?batch_size=64,?max_latency=0.1)

#?用Streamer異步調用predict函數
outputs?=?streamer.predict(batch_inouts)

然后你的 web server 需要開啟多線程(或協程)即可。?
短短幾行代碼,通常可以實現數十(batch_size/batch_per_request)倍的加速。
分布式GPU worker?
上面的例子是在 web server 進程中,開啟子線程作為 GPU worker 進行 batch predict,用線程間隊列進行通信和排隊。?
實際項目中 web server 的性能(QPS)遠高于 GPU 模型的性能,所以我們支持一個 web server 搭配多個 GPU worker 進程。
import?multiprocessing;?multiprocessing.set_start_method("spawn",?force=True)from?service_streamer?import?Streamer#?spawn出4個gpu?worker進程streamer?=?Streamer(model.predict,?64,?0.1,?worker_num=4)outputs?=?streamer.redict(batch)
multiprocessing.set_start_method("spawn",?force=True)
from?service_streamer?import?Streamer

#?spawn出4個gpu?worker進程
streamer?=?Streamer(model.predict,?64,?0.1,?worker_num=4
outputs?=?streamer.redict(batch)

Streamer 默認采用 spawn 子進程運行 gpu worker,利用進程間隊列進行通信和排隊,將大量的請求分配到多個 worker 中處理,再將模型 batch predict 的結果傳回到對應的 web server,并且返回到對應的 http response。


上面這種方式定義簡單,但是主進程初始化模型,多占了一份顯存,并且模型只能運行在同一塊 GPU 上,所以我們提供了 ManageModel 類,方便模型 lazy 初始化和遷移,以支持多 GPU。
from?service_streamer?import?ManagedModelclass?ManagedBertModel(ManagedModel):???def?init_model(self):???????self.model?=?Model(?)??def?predict(self,?batch):??????return?self.model.predict(batch)?#?spawn出4個gpu?worker進程,平均分數在0/1/2/3號GPU上streamer?=?Streamer(ManagedBertModel,?64,?0.1,?worker_num=4,cuda_devices=(0,1,2,3))outputs?=?streamer.predict(batch)import?ManagedModel

class?ManagedBertModel(ManagedModel):

???def?init_model(self):
???????self.model?=?Model(?)

??def?predict(self,?batch):
??????return?self.model.predict(batch)?

#?spawn出4個gpu?worker進程,平均分數在0/1/2/3號GPU上
streamer?=?Streamer(ManagedBertModel,?64,?0.1,?worker_num=4,cuda_devices=(0,1,2,3))
outputs?=?streamer.predict(batch)


分布式web server?
有時候,你的 web server 中需要進行一些 CPU 密集型計算,比如圖像、文本預處理,再分配到 GPU worker 進入模型。CPU 資源往往會成為性能瓶頸,于是我們也提供了多 web server 搭配(單個或多個)GPU worker 的模式。
使用 RedisStreamer 指定所有 web server 和 GPU worker 共用的 redis broker 地址。
#?默認參數可以省略,使用localhost:6379streamer?=?RedisStreamer(redis_broker="172.22.22.22:6379")
streamer?=?RedisStreamer
(redis_broker="172.22.22.22:6379")


然后跟任意 python web server 的部署一樣,用 gunicorn 或 uwsgi 實現反向代理和負載均衡。
cd?examplegunicorn?-c?redis_streamer_gunicorn.py?flask_example:app

這樣每個請求會負載均衡到每個 web server 中進行 CPU 預處理,然后均勻的分布到 GPU worke 中進行模型 predict。

Future API


如果你使用過任意 concurrent 庫,應該對 future 不陌生。當你的使用場景不是 web service,又想使用 service_streamer 進行排隊或者分布式 GPU 計算,可以直接使用 Future API。
from?service_streamer?import?ThreadedStreamerstreamer?=?ThreadedStreamer(model.predict,?64,?0.1)xs?={}for?i?in?range(200):????future?=?streamer.submit(["Happy?birthday?to?[MASK]",????????????????????????????????????????????"Today?is?my?lucky?[MASK]"])?????xs.append(future)#?先拿到所有future對象,再等待異步返回for?future?in?xs:?????outputs?=?future.result()?????print(outputs)import?ThreadedStreamer
streamer?=?ThreadedStreamer(model.predict,?64,?0.1)

xs?={}
for?i?in?range(200):
????future?=?streamer.submit(["Happy?birthday?to?[MASK]",?
???????????????????????????????????????????"Today?is?my?lucky?[MASK]"])
?????xs.append(future)

#?先拿到所有future對象,再等待異步返回
for?future?in?xs:
?????outputs?=?future.result()
?????print(outputs)

基準測試


如何做基準測試
我們使用 wrk 來使做基準測試。?
環境

單個GPU進程
#?start?flask?threaded?serverpython?example/flask_example.py#?benchmark?naive?api?without?service_streamer./wrk?-t?4?-c?128?-d?20s?--timeout=10s?-s?scripts/streamer.lua?http://127.0.0.1:5005/naive#?benchmark?stream?api?with?service_streamer./wrk?-t?4?-c?128?-d?20s?--timeout=10s?-s?scripts/streamer.lua?http://127.0.0.1:5005/naive
python?example/flask_example.py

#?benchmark?naive?api?without?service_streamer
./wrk?-t?4?-c?128?-d?20s?--timeout=10s?-s?scripts/streamer.lua?http://127.0.0.1:5005/naive

#?benchmark?stream?api?with?service_streamer
./wrk?-t?4?-c?128?-d?20s?--timeout=10s?-s?scripts/streamer.lua?http://127.0.0.1:5005/naive



多個GPU進程?
這里對比單 web server 進程的情況下,多 GPU worker 的性能,驗證通過和負載均衡機制的性能損耗。Flask 多線程 server 已經成為性能瓶頸,故采用 gevent server。


利用Future API使用多個GPU?
為了規避 web server 的性能瓶頸,我們使用底層 Future API 本地測試多 GPU worker 的 benchmark。


可以看出 service_streamer 的性能跟 GPUworker 數量及乎成線性關系,其中進程間通信的效率略高于 redis 通信。




點擊以下標題查看更多往期內容:?


  • KDD Cup 2019 AutoML Track冠軍團隊技術分享

  • 神經網絡架構搜索(NAS)綜述 | 附資料推薦

  • 小米拍照黑科技:基于NAS的圖像超分辨率算法

  • 深度解讀:小米AI實驗室最新成果FairNAS

  • 自動機器學習(AutoML)最新綜述

  • NAS-FPN:基于自動架構搜索的特征金字塔網絡




#投 稿 通 道#

?讓你的論文被更多人看到?



如何才能讓更多的優質內容以更短路徑到達讀者群體,縮短讀者尋找優質內容的成本呢?答案就是:你不認識的人。


總有一些你不認識的人,知道你想知道的東西。PaperWeekly 或許可以成為一座橋梁,促使不同背景、不同方向的學者和學術靈感相互碰撞,迸發出更多的可能性。


PaperWeekly 鼓勵高校實驗室或個人,在我們的平臺上分享各類優質內容,可以是最新論文解讀,也可以是學習心得技術干貨。我們的目的只有一個,讓知識真正流動起來。


??來稿標準:

? 稿件確系個人原創作品,來稿需注明作者個人信息(姓名+學校/工作單位+學歷/職位+研究方向)?

? 如果文章并非首發,請在投稿時提醒并附上所有已發布鏈接?

? PaperWeekly 默認每篇文章都是首發,均會添加“原創”標志


? 投稿郵箱:

? 投稿郵箱:hr@paperweekly.site?

? 所有文章配圖,請單獨在附件中發送?

? 請留下即時聯系方式(微信或手機),以便我們在編輯發布時和作者溝通




?


現在,在「知乎」也能找到我們了

進入知乎首頁搜索「PaperWeekly」

點擊「關注」訂閱我們的專欄吧



關于PaperWeekly


PaperWeekly 是一個推薦、解讀、討論、報道人工智能前沿論文成果的學術平臺。如果你研究或從事 AI 領域,歡迎在公眾號后臺點擊「交流群」,小助手將把你帶入 PaperWeekly 的交流群里。


▽ 點擊 |?閱讀原文?| 訪問項目主頁

總結

以上是生活随笔為你收集整理的开源项目 | 五分钟搭建BERT服务,实现1000+QPS的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。