前言
最近團(tuán)隊(duì)的模型部署上線終于全面開始用上docker了,這感覺凉泄,真香躏尉!
講道理,docker是天然的微服務(wù)后众,確實(shí)是能敏捷高效的解決深度學(xué)習(xí)這一塊的幾個(gè)痛點(diǎn)胀糜。
- 部分神經(jīng)網(wǎng)絡(luò)框架比如caffe依賴過重颅拦,安裝困難。
- 各種網(wǎng)絡(luò)模型未做工程化優(yōu)化教藻,部署困難距帅。
- tensorflow等框架對GPU等硬件的占用難以靈活控制。
對于做應(yīng)用來說括堤,這些問題諸如對GPU的硬件的管理碌秸,對復(fù)雜依賴的部署,而這些正好就是docker的強(qiáng)項(xiàng)悄窃。而python本身表達(dá)能力強(qiáng)讥电,可以以很短的代碼量達(dá)成我們的目的。
部署
具體的部署步驟涉及這幾個(gè)工具鏈:
- Dockerfile進(jìn)行模型的鏡像部署轧抗。
- docker-py進(jìn)行container的啟動(dòng)和關(guān)閉恩敌。
- grpc和進(jìn)行模型的外部通信。
- python的with語句表達(dá)模型的加載和資源的釋放横媚。
- gitlab進(jìn)行內(nèi)網(wǎng)的代碼分發(fā)和版本控制纠炮。
整個(gè)接口的調(diào)用精簡成面向?qū)ο蟮恼{(diào)用方式,with語句進(jìn)入時(shí)啟動(dòng)模型灯蝴,占用GPU恢口,打開rpc調(diào)用端口,之后在調(diào)用結(jié)束后退出模型绽乔,釋放資源弧蝇,整個(gè)調(diào)用過程就簡化成如下樣子:
其中Model_Docker是這樣的:
整個(gè)流程是這么個(gè)步驟:
- init方法獲得docker client。get_container方法實(shí)例化一個(gè)container折砸。
- with語句進(jìn)入接口的enter方法看疗,負(fù)責(zé)獲取container實(shí)例和實(shí)例內(nèi)模型啟動(dòng)結(jié)束的flag。
- with語句清理接口的exit方法睦授,負(fù)責(zé)實(shí)例的關(guān)閉两芳。
- run方法通過grpc調(diào)用docker內(nèi)模型和返回結(jié)果。
docker-py是一個(gè)docker的python接口去枷,docker除了cmdline的操作方式怖辆,還提供了REST的調(diào)用接口,docker-py就是其中一個(gè)很人性化的封裝删顶,具體使用可見官方文檔竖螃。
container的實(shí)例化中有這幾個(gè)地方需要注意:
- runtime需要用nvidia,與使用nvidia-docker效果一樣逗余。
- detach是后臺模式特咆,與-d效果一樣。
- auto_remove是自動(dòng)刪除录粱,與--rm效果類似腻格。
- environment 來設(shè)定CUDA_VISIBLE_DEVICES画拾。
- ports 來指定導(dǎo)出端口映射。
除了docker-py調(diào)用中的這些技巧菜职,還有如下幾個(gè)指令在構(gòu)建過程中值得注意青抛。
1、grpc的編譯酬核,這里沒啥好說的蜜另,和grpc的官方說明文檔里一樣。
RUN python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. mode.proto
2愁茁、docker image的構(gòu)建蚕钦,有時(shí)候構(gòu)建需要添加--no-cache,避免遠(yuǎn)程資源更新了鹅很,docker構(gòu)建卻沒重新。
docker build --no-cache -t name .
3罪帖、pip安裝的時(shí)候需要添加幾個(gè)參數(shù)促煮,-r指定.txt安裝,-i指定清華鏡像為安裝源整袁,--no-cache-dir壓縮docker鏡像菠齿。
RUN pip install -r requirements_docker.txt -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir
后記
這一輪AI浪潮撲騰到今天,也積累了大量可落地的框架和應(yīng)用坐昙。不過在github歡快的clone代碼的時(shí)候绳匀,一直注意到一些事。和web等領(lǐng)域不同的是炸客,幾乎所有模型幾乎都是以源代碼的形式分發(fā)的疾棵,很少有工程化的封裝,更別說封裝成庫來部署了痹仙。就拿現(xiàn)在我在做的目標(biāo)檢測和文字識別的幾個(gè)模型來說是尔,yolo、fasterrcnn开仰、ctpn和crnn等都是這樣拟枚。
當(dāng)然這也好理解,這些開源作品基本都是大佬在水文章之余寫的众弓,而且一個(gè)完整的模型包括訓(xùn)練恩溅、測試和預(yù)測,模型在公開數(shù)據(jù)集上的訓(xùn)練效果才是關(guān)鍵谓娃,工程化的問題并不是最重要的事情脚乡,不過我還是想吐槽一下。
比如fasterrcnn中訓(xùn)練數(shù)據(jù)是寫死的傻粘,準(zhǔn)備好訓(xùn)練集后得通過一個(gè)軟連接將訓(xùn)練集和訓(xùn)練數(shù)據(jù)替換掉每窖。這還不是最毒瘤的帮掉,較新的ctpn是繼承自fasterrcnn,也是采用這種方法.
又比如在導(dǎo)入數(shù)據(jù)階段也是各用各的法子窒典,這些做法有往往采用多線程和多進(jìn)程蟆炊,結(jié)果管理不好,一大堆死線程不說瀑志,還經(jīng)常把cpu跑滿涩搓,用過的模型中darkflow和east都有這樣的問題。
還有在寫inference是劈猪,還常常遇到需要修改輸入輸出tensor的情況昧甘,在輸入端加placeholder,稍微對tensorflow不熟战得,同時(shí)還需要修改一些在預(yù)測階段有所改變的tensor充边。確實(shí)是很不人道。
最后想提一點(diǎn)常侦,這種部署方式除了部署時(shí)靈活方便浇冰,另外一個(gè)額外的好處就是使用jupyter時(shí)也方便,在jupyter使用時(shí)最常見的問題有兩個(gè)聋亡,一個(gè)是需要經(jīng)常使用set_env去設(shè)置CUDA_VISIBLE_DEVICES肘习,另一個(gè)是用完了得把notebook關(guān)掉,不然jupyter進(jìn)程會(huì)一直占用GPU坡倔。