歡迎關注公眾號:七只的Coding日志,[更多鏈接](https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=Mzk0ODA5NTc5MQ==&uin=&key=&devicetype=Windows+10+x64&version=6302019c&lang=zh_CN&a8scene=7&fontgear=2)
實現從項目調研、數據收集、數據預處理、深度卷積神經網絡訓練再到服務器部署的人臉表情識別小項目
一、需求
1、簡單的demo演示,只要看看效果的,像是學校里面的demo展示這種
caffe、tf、pytorch等框架隨便選一個,切到test模式,拿python跑一跑就好,順手寫個簡單的GUI展示結果
高級一點,可以用CPython包一層接口,然后用C++工程去調用
2、要放到服務器上去跑,但一不要求吞吐二不要求時延的那種,說白了還是有點玩玩的意思
caffe、tf、pytorch等框架隨便選一個,按照官方的部署教程,老老實實用C++部署,例如pytorch模型用工具導到libtorch下跑(官方有教程,很簡單)
這種還是沒有脫離框架,有很多為訓練方便保留的特性沒有去除,性能并不是最優的;
另外,這些框架要么CPU,要么NVIDIA GPU,對硬件平臺有要求,不靈活;
還有,框架是真心大,占內存(tf還占顯存),占磁盤
3、放到服務器上跑,要求吞吐和時延(重點是吞吐)
這種應用在互聯網企業居多,一般是互聯網產品的后端AI計算,例如人臉驗證、語音服務、應用了深度學習的智能推薦等。
由于一般是大規模部署,這時不僅僅要考慮吞吐和時延,還要考慮功耗和成本。所以除了軟件外,硬件也會下功夫,比如使用推理專用的NVIDIA P4、寒武紀MLU100等。這些推理卡比桌面級顯卡功耗低,單位能耗下計算效率更高,且硬件結構更適合高吞吐量的情況
軟件上,一般都不會直接上深度學習框架。對于NVIDIA的產品,一般都會使用TensorRT來加速(我記得NVIDIA好像還有TensorRT inference server什么的,名字記不清了,反正是不僅可以加速前傳,還順手幫忙調度了)。TensorRT用了CUDA、CUDNN,而且還有圖優化、fp16、int8量化等。反正用NVIDIA的一套硬軟件就對了
4、放在NVIDIA嵌入式平臺上跑,注重時延
比如PX2、TX2、Xavier等,參考上面(用全家桶就對了),也就是貴一點嘛
5、放在其他嵌入式平臺上跑,注重時延
硬件方面,要根據模型計算量和時延要求,結合成本和功耗要求,選合適的嵌入式平臺。
比如模型計算量大的,可能就要選擇帶GPU的SoC,用opencl/opengl/vulkan編程;也可以試試NPU,不過現在NPU支持的算子不多,一些自定義Op多的網絡可能部署不上去
對于小模型,或者幀率要求不高的,可能用CPU就夠了,不過一般需要做點優化(剪枝、量化、SIMD、匯編、Winograd等)
順帶一提,在手機上部署深度學習模型也可以歸在此列,只不過硬件沒得選,用戶用什么手機你就得部署在什么手機上23333。為老舊手機部署才是最為頭疼的
上述部署和優化的軟件工作,在一些移動端開源框架都有人做掉了,一般拿來改改就可以用了,性能都不錯。
6、上述部署方案不滿足我的需求
比如開源移動端框架速度不夠——自己寫一套。比如像商湯、曠世、Momenta都有自己的前傳框架,性能應該都比開源框架好。只不過自己寫一套比較費時費力,且如果沒有經驗的話,很有可能費半天勁寫不好。
就目前來說,我打算將需求定位到2,后期在2的基礎上考慮吞吐和延遲問題,從而能夠進一步達到需求3和5(位于手機端部署)
二、部署方面問題
模型部署就是在某一框架內訓練好的模型(權重文件),通過具體框架進行模型轉化或者直接使用對應語言所提供的API接口,load、get一系列操作,使得訓練好的“黑箱”能得到實際應用。這種方式可能是簡單的pyinstaller庫進行簡單的封裝、也可以是pyqt進行界面集成、接口調用,或者使用flask或者Django框架進行前端和后臺服務器的嵌入,這些總體來說,都算是模型部署。
1、首先,不得不提Docker部署模型
Docker的前生是LXC,全名Linux Container,是一種輕量級的虛擬化手段,以便隔離進程和資源。容器是指將單個系統管理的資源劃分到孤立的組中,有效地安排資源使用需求。總之,LXC是一種操作系統層次上的資源虛擬化,提供了一個自己的進程和網絡空間的虛擬環境。
什么是Docker呢?? Docker底層使用了LXC實現,在此基礎上,增添了更多強大的功能。Docker屬于一種開源應用容器引擎,是基于go語言開發并遵循apache2.0協議開源。
優點:?可以讓開發者打包他們的應用以及依賴包到一個輕量級、可移植的容器中,然后發布到任何流行的linux服務器,也可以實現虛擬化。
Docker總體架構:
由于本次輕量化網絡結構部署,因此采用Docker作為容器。
2、Docker基本概念
Docker包括三個基本概念:
? ??——鏡像(Image)
? ??——容器(Container)
? ??——倉庫(Repository)
2.1?鏡像(Image)——一個特殊的文件系統
Docker 鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些為運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。?鏡像不包含任何動態數據,其內容在構建之后也不會被改變。
鏡像構建時,會一層層構建,前一層是后一層的基礎。每一層構建完就不會再發生改變,后一層上的任何改變只發生在自己這一層。比如,刪除前一層文件的操作,實際不是真的刪除前一層的文件,而是僅在當前層標記為該文件已刪除。在最終容器運行的時候,雖然不會看到這個文件,但是實際上該文件會一直跟隨鏡像。因此,在構建鏡像的時候,需要額外小心,每一層盡量只包含該層需要添加的東西,任何額外的東西應該在該層構建結束前清理掉。
2.2 容器(Container)——鏡像運行時的實體
鏡像(Image)和容器(Container)的關系,就像是面向對象程序設計中的類和實例 一樣,鏡像是靜態的定義,容器是鏡像運行時的實體。容器可以被創建、啟動、停止、刪除、暫停等?。
容器的實質是進程,但與直接在宿主執行的進程不同,容器進程運行于自己的獨立的命名空間。前面講過鏡像使用的是分層存儲,容器也是如此。
容器存儲層的生存周期和容器一樣,容器消亡時,容器存儲層也隨之消亡。因此,任何保存于容器存儲層的信息都會隨容器刪除而丟失。
按照 Docker 最佳實踐的要求,容器不應該向其存儲層內寫入任何數據?,容器存儲層要保持無狀態化。所有的文件寫入操作,都應該使用數據卷(Volume)、或者綁定宿主目錄,在這些位置的讀寫會跳過容器存儲層,直接對宿主(或網絡存儲)發生讀寫,其性能和穩定性更高。數據卷的生存周期獨立于容器,容器消亡,數據卷不會消亡。因此,?使用數據卷后,容器可以隨意刪除、重新 run ,數據卻不會丟失。
2.3 倉庫(Repository)——集中存放鏡像文件的地方
鏡像構建完成后,可以很容易的在當前宿主上運行,但是,?如果需要在其它服務器上使用這個鏡像,我們就需要一個集中的存儲、分發鏡像的服務,Docker Registry就是這樣的服務。
一個 Docker Registry中可以包含多個倉庫(Repository);每個倉庫可以包含多個標簽(Tag);每個標簽對應一個鏡像。所以說:鏡像倉庫是Docker用來集中存放鏡像文件的地方類似于我們之前常用的代碼倉庫。
3、“Docker - Build, Ship, and Run Any App, Anywhere”
——Build(構建鏡像)?: 鏡像就像是集裝箱包括文件以及運行環境等等資源。
——Ship(運輸鏡像)?:主機和倉庫間運輸,這里的倉庫就像是超級碼頭一樣。
——Run (運行鏡像)?:運行的鏡像就是一個容器,容器就是運行程序的地方。
4、Docker安裝
Docker也是支持其他如CentOS, Mac OS X, Windows等平臺。Docker運行對內核要求比較高,一般建議直接在Ubuntu平臺運行。
CentOS中安裝docker教程,Windows10中安裝docker教程,Windows10中docker的安裝與使用,Mac系統docker安裝