手把手教你如何部署深度學習模型
我剛剛訓練了機器學習模型——那麼現在呢?這篇文章介紹了一種快速的方法,將經過訓練的機器學習模型部署到生產中。請閱讀以下內容:如果您已經成功地使用諸如Tensorflow或Caffe這樣的ML框架來培訓ML模型,那麼您最好先做一個演示,最好早一點而不是晚一點,而且您更喜歡更便捷的解決方案,而不是將整個技術堆棧都打包。
一、ML在生產中
當我們第一次進入Hive的機器學習空間時,我們已經擁有了數百萬個標記為圖像的地面實況,這使得我們可以在一個星期內訓練一個最先進的深度卷積圖像分類模型(即隨機權重),專門用於我們的用例。 然而,更典型的ML使用案例通常是數百幅圖像的數量級,為此我建議微調現有的模型。例如,https://www.tensorflow.org/tutorials/image_retraining有一個很好的教程關於如何微調Imagenet模型(訓練1.2圖片,1000類)來對花卉樣本數據(3647圖片,5類)進行分類。
對於連接Tensorflow教程的快速tl;dr,在安裝bazel和tensorflow之後,您需要運行以下代碼,這需要大約30分鐘的時間來搭建和5分鐘的時間來訓練:
或者,如果您安裝了Docker,則可以使用以下預構建的Docker鏡像:
在容器內的互動式shell中運行上述命令;如果您願意,您也可以跟著這個文章的其他部分在容器內操作。
現在,tensorflow已經將模型信息保存到/tmp/output_graph.pb和/tmp/output_labels.txt中,這些作為命令行參數傳遞給label_image.py腳本。 Google的image_recognition教程也鏈接到另一個推理腳本,但是現在我們將堅持使用label_image.py。
將一次性推斷轉換為在線推斷(Tensorflow)
如果我們只想接受來自標準輸入的文件名,每行一個,我們就可以很容易地進行「在線」推斷:
從性能的角度來看,這很糟糕——我們正在重新載入神經網路、權重、整個Tensorflow框架和python本身,對於每個輸入示例都是如此!
我們可以做得更好。 讓我們開始編輯label_image.py腳本——對於我來說,它位於bazel-bin / tensorflow / examples / image_retraining / label_image.runfiles / org_tensorflow / tensorflow / examples / image_retraining / label_image.py中。
讓我們改變行
到
這確實快了很多,但是這還不是我們能做的最好的!
原因是tf.Session()在第100行上的sess構造。Tensorflow基本上每次調用run_graph時都將所有的計算載入到內存中。當您開始嘗試在GPU上進行推理時,這一點就變得很明顯了——您可以看到GPU內存隨著Tensorflow在GPU上載入和卸載模型參數而上下移動。據我所知,這種結構並不存在於其他ML框架中,比如Caffe或Pytorch。
然後解決方案是拉出with語句,並傳遞一個sess變數到run_graph:
(在https://github.com/hiveml/simple-ml-serving/blob/master/label_image.py上看代碼)
如果你運行這個程序,你會發現每張圖片載入大約需要0.1秒,對於在線使用來說足夠快。
將一次性推斷轉換為在線推理(其他ML框架)
Caffe使用它的net.forward代碼,這個代碼很容易放入可調用的框架中:請參閱http://nbviewer.jupyter.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb
Mxnet也是非常獨特的:它實際上具有開源的隨時可用的推理伺服器代碼:https://github.com/awslabs/mxnet-model-server。
部署
計劃是將這些代碼包裝在Flask應用程序中。 如果您還沒有聽說過它,Flask是一個非常輕量級的Python Web框架,它允許您用最少的工作來創建一個http api伺服器。
作為一個快速的參考,這是一個flask應用程序,它接收來自多個表單數據的POST請求:
這是對應的flask應用程序連接到run_graph上面:
這看起來很好,除了flask和tensorflow都是完全同步的——按照接收到的順序一次處理一個請求,而Tensorflow在進行圖像分類時完全佔用線程。
正如它所寫的那樣,速度瓶頸可能還在實際的計算工作中,所以升級Flask包裝代碼沒有太多的意義。現在,也許這段代碼足夠處理您的負載了。
有兩種很明顯的方法可以提高請求的通用性:通過增加worker的數量來橫向放大,這在下一節將會介紹,或者通過使用GPU和批處理邏輯來縱向擴展。實現後者需要一個能夠同時處理多個掛起請求的web伺服器,並決定是否繼續等待更大的批處理,或者將其發送到Tensorflow圖形線程,以便進行分類,而這對於Flask應用程序是非常不適合。有兩種可能性,使用Twisted + Klein來保存Python代碼,或者如果您更喜歡第一個類的事件循環支持,並且能夠連接到非Python ML框架(如Torch),則可以使用Node.js + ZeroMQ。
擴展:負載平衡和服務發現
好的,現在我們有一台伺服器來服務我們的模型,但也許它太慢了,或者我們的負載變得太高了。我們想要啟動更多的這些伺服器——我們如何在每個伺服器上分配請求?
普通的方法是添加一個代理層,可能是haproxy或nginx,它平衡後端伺服器之間的負載,同時向客戶機提供一個統一的介面。為了在本節稍後使用,以下是運行基本Node.js負載均衡器http代理的一些示例代碼:
為了自動檢測後端伺服器的數量和位置,人們通常會使用「服務發現」工具,該工具可能與負載平衡器捆綁在一起或者是單獨的。一些知名的是Consul和Zookeeper。設置和學習如何使用它不在本文的討論範圍之內,所以我使用了node.js服務發現包seaport來包含一個非常基本的代理。
代理代碼:
Worker 代碼:
但是,對於ML,這個設置會遇到帶寬問題。
在任何地方,每秒幾十到幾百張圖像,系統就會被網路帶寬阻塞。在目前的設置中,所有的數據都必須通過我們的單個seaport 主站,這是呈現給客戶端的單個端點。
為了解決這個問題,我們要求我們的客戶端不在http://127.0.0.1:12480點擊單個端點,而是在後端伺服器之間自動輪換點擊。如果你知道一些網路,這聽起來就像DNS的工作!
但是,設置自定義的DNS伺服器已經超出了本文的範圍。 相反,通過更改客戶端來遵循兩步「手動DNS」協議,我們可以重新使用我們的基本seaport代理來實現客戶端直接連接到其伺服器的「點對點」協議:
代理代碼:
(worker代碼與上述相同)
客戶端代碼:
RPC部署
即將到來!上面的Flask版本被ZeroMQ替換。
結論和進一步閱讀
在這一點上,你應該有一些在生產中工作的東西,但它肯定不是未來的保障。本指南中沒有涉及到的幾個重要的主題:
自動部署和設置新的硬體。
如果你在自己的硬體上,值得注意的工具包括Openstack/VMware,Chef / Puppet用於安裝Docker和處理網路路由,以及Docker用於安裝Tensorflow、Python和其他任何東西。
如果你在雲端,Kubernetes或Marathon/Mesos也很棒。
模型版本管理
在開始的時候手動處理並不太難。
Tensorflow Serving是一個很好的工具,它可以非常徹底地處理這個問題,以及批處理和整體部署。缺點是設置和編寫客戶端代碼有點困難,而且不支持Caffe/PyTorch。
如何從Matlab移植你的ML代碼
不要在生產中使用matlab。
GPU驅動程序,Cuda,CUDNN
使用nvidia-docker並嘗試在線查找一些Docker文件。
後處理圖層。一旦您在生產中獲得了一些不同的ML模型,您可能會開始想要混合併匹配不同的用例——只有在模型B不確定的情況下運行模型A,在Caffe中運行模型C,並將結果傳遞給Tensorflow中的模型D等等。
原文:https://thehive.ai/blog/simple-ml-serving?spm=a2c4e.11153959.blogcont428414.27.51ef9992xr9pvq
※國科大在揭秘愛因斯坦統一場論的研究中取得突破
※滴滴成立AI Labs加大人工智慧領域投入 布局智慧交通
TAG:AI講堂 |