在幾分鐘內構建強大的可用於生產的深度學習視覺模型

  • 2019 年 10 月 7 日
  • 筆記

作者 | Dipanjan

來源 | Medium

編輯 | 程式碼醫生團隊

介紹

得益於更快的計算,更好的存儲和易於使用的軟體,基於深度學習的解決方案絕對可以看到從概念驗證隧道進入現實世界的曙光!看到深度學習模型已廣泛應用於該行業的各個領域,包括醫療保健,金融,零售,技術,物流,食品技術,農業等!考慮到深度學習模型需要大量資源並且經常需要大量計算的事實,因此我們需要暫停片刻,並考慮一下最終用戶使用模型時的推斷和服務時間。

在進行原型設計時,需要對靜態批次的數據進行訓練和執行模型推斷。但是,當希望以Web服務或API的形式使用模型時,這種方法論和程式碼工件就無法發揮作用。通常需要一個健壯且低延遲的模型服務層,該層應能夠更快,更輕鬆地滿足模型推理請求。本文試圖給出一個簡單而全面的動手概述,說明如何利用TensorFlow Serving為電腦視覺提供深度學習模型。本文將涉及很多內容,還將包含許多動手程式碼,可以根據自己的實踐採用這些程式碼。將在本文中介紹以下主題:

  • 什麼是服務?
  • TensorFlow服務概述
  • TensorFlow服務架構
  • 模型服務方法
  • 主要目標-建立服裝分類器
  • 訓練簡單的CNN模型
  • 微調預訓練的ResNet-50 CNN模型
  • TensorFlow服務的保存模型
  • 通過CPU推論服務模型
  • 使用Docker服務模型進行GPU推理
  • 獎勵:使用Flask和TensorFlow服務構建服裝分類器API

什麼是服務?

服務,或更具體地說,模型服務是一種在訓練模型後使用或應用模型進行推理的技術。通常,這涉及擁有伺服器-客戶端體系結構以及服務或公開訓練有素的模型以進行推理。

考慮到將在本文中關注的問題-影像分類,將為模型提供一些特定的訪問模式。在最終用戶或客戶端上,將有一個需要標記或分類的輸入影像。需要將該影像轉換為特定的編碼格式,將其包裝在帶有標頭的特定JSON負載中,然後將其發送到通常應託管在伺服器上的Web Service API。API調用將調用預訓練模型進行預測,並將推理結果作為從伺服器到客戶端的JSON響應提供服務。

TensorFlow服務概述

TensorFlow服務有很多很棒的文章,包括官方文檔,絕對應該檢查一下。在本部分中,將簡要概述TensorFlow Serving的基本知識以及為什麼需要它。為了生產深度學習或機器學習模型,需要一個強大的系統,該系統可以幫助使模型快速,一致地滿足請求。TensorFlow Serving就是這樣一個框架,它是一個針對機器學習模型的靈活,高性能的服務系統,專門針對生產環境而設計。

儘管始終可以構建自己的服務管道和系統,但是使用TensorFlow服務有很多好處。

  • 在保持相同的伺服器體系結構和API的同時,部署新演算法和實驗非常容易。
  • 不僅可以與TensorFlow模型一起使用,而且可以輕鬆擴展以服務於其他類型的模型和數據。
  • 可用於同時服務多個模型和模型版本。
  • 高效的模型生命周期管理。
  • 可以與Docker和Kubernetes之類的工具集成以實現更大的可擴展性。

TensorFlow服務架構

在本節中,將簡要研究TensorFlow Serving背後的體系結構的要點。要深入了解該體系結構,建議再次檢查官方文檔。

服務是TensorFlow服務架構中的核心抽象。通常,可服務對象是客戶端用來執行諸如模型推斷之類的計算的基礎對象。單個Servable可能包含一個模型甚至多個模型。下圖展示了可服務對象的典型壽命。

可服務人員的壽命

通常,此體系結構中包含多個組件。可服務流是可服務版本的序列。裝載機管理可服務的生命周期,具有裝載和卸載可服務的API。源是用於查找和提供可服務項並可以維護在多個可服務項之間共享的狀態的插件模組。經理負責處理可食用物品的整個生命周期,包括裝載,卸載和供應可食用物品。使用標準的TensorFlow Serving API,TensorFlow Serving Core可以管理服務項目的生命周期和指標。

模型服務方法

在討論主要目標並訓練模型之前,簡要討論一下將遵循的模型服務方法,假設已經訓練了一些基於視覺的深度學習模型。下圖顯示了要遵循的關鍵步驟。

因此,將主要針對服務模型的關鍵步驟包括:

  • 模型訓練:要為任何模型服務,需要首先訓練模型!在本文中,將利用tf.kerasTensorFlow中的API,這有助於輕鬆訓練深度學習模型。
  • 導出模型:在這裡,需要將訓練有素的模型導出為TF Serving可以使用的特定格式。TensorFlow將SavedModel格式提供為導出模型的通用格式。這將在定義明確的目錄層次結構中創建一個protobuf文件,並且還將包含如下所示的版本號。

TensorFlow Serving允許我們選擇在進行推理請求時要使用的模型版本或「可服務」版本。每個版本都將導出到給定路徑下的不同子目錄,如上圖所示。TensorFlow提供便利功能tf.saved_model.simple_save() ,可幫助輕鬆保存這些模型。

  • 託管TensorFlow服務模型伺服器:在這裡,將使用TensorFlow服務框架來託管保存的模型。將專註於基於本地TF Serving的CPU推斷安裝,還將展示如何將基於Docker容器的TF Serving實例用於GPU推斷。在本文結尾,還利用TF Serving之上的Flask框架來構建自己的自定義服務API。
  • 發出伺服器請求:伺服器啟動並運行後,可以通過gRPC或HTTP對其進行請求。對於這兩種方法,通常創建帶有必要內容和標頭的有效負載消息,並將其發送到伺服器。伺服器又應返回包含預測的消息。將使用該requests模組進行HTTP請求。

主要目標-建立服裝分類器

關於關鍵目標,將在這裡簡化。將基於Zalando的商品圖片,在非常著名的Fashion MNIST數據集上訓練模型,從而建立一個簡單的服裝分類器,該模型包括6萬個示例的訓練集和10,000個示例的測試集。每個示例都是一個28×28灰度影像,與來自10個類別的標籤相關聯。想法是將這些影像分類為10個類別中的服裝類別,將在這些類別上訓練模型。

https://github.com/zalandoresearch/fashion-mnist

Fashion-MNIST示例

在著重於模型服務之前,將在本文中構建以下兩個深度學習CNN(卷積神經網路)分類器。

  • 從頭開始訓練的簡單CNN
  • 微調經過預訓練的ResNet-50 CNN

本文的目的是將更多的精力放在部署和服務方面,因此不會花很多時間討論模型架構或訓練和微調。如有必要,請隨時在本文結尾處查看有關CNN的簡要說明。測試本文的平台是帶有NVIDIA Tesla T4 的Google Cloud Platform深度學習VM,這使得在雲上進行實驗變得非常容易!

https://cloud.google.com/deep-learning-vm/

載入依賴項和數據

在訓練深度學習模型之前,載入必要的依賴項和數據集以訓練深度學習模型。

1.14.0

在這裡使用TensorFlow GPU版本1.14,但是考慮到主要關注tf.kerasAPI,可以輕鬆將其擴展到TensorFlow 2.0 。現在可以利用TensorFlow本身來載入Fashion-MNIST數據集。

Train_images.shape: (60000, 28, 28), of uint8

Test_images.shape: (10000, 28, 28), of uint8

根據前面提到的內容,有60000個訓練影像和10000個大小的測試影像28×28。現在,將開始訓練深度學習模型。

訓練簡單的CNN模型

在本節中,將從頭開始訓練基本的2層CNN模型。在訓練模型之前,確實需要重塑數據,而以下程式碼也將處理這些數據。

Train_images.shape: (60000, 28, 28, 1), of uint8

Test_images.shape: (10000, 28, 28, 1), of uint8

還可以查看一些影像的外觀,如以下快照所示。

現在,將構建基本的2層CNN模型架構。

訓練模型10個時間段,然後看看其性能。

請注意,訓練了90%的訓練數據,並驗證了10%的訓練數據。性能在驗證集上相當不錯。讓保存模型,然後檢查測試數據集的性能。

測試數據集的總體模型性能為提供了91%的f1分數,這非常好!

微調預訓練的ResNet-50 CNN模型

遷移學習在電腦視覺和自然語言處理領域取得了空前的成功,其預訓練的模型通常會從頭開始勝過訓練模型。在這裡,將使用ResNet-50模型,該模型通過在Fashion-MNIST數據集上進行微調而在ImageNet數據集上進行了預訓練。ResNet-50模型是建立在ImageNet資料庫上的50個卷積塊(每個塊中有幾個層)的深度學習網路。該模型共有175多個層,是一個非常深的網路。ResNet代表殘差網路。

將使用的ResNet-50模型包括5個階段,每個階段都有一個卷積和標識塊。每個卷積塊具有3個卷積層,每個標識塊也具有3個卷積層。本節的重點將是採用預先訓練的ResNet-50模型,然後對網路中的所有層進行完整的微調。將像往常一樣添加常規的密集層和輸出層。

該模型非常龐大,可以根據可訓練參數的數量看到證據!在訓練模型之前,由於ResNet模型是在彩色影像上訓練的,因此需要將灰度影像轉換為具有三個通道的影像。除此之外,ResNet模型可接受的最小尺寸為32×32,因此需要調整影像大小。

Train_images.shape: (60000, 32, 32, 3), of float32

Test_images.shape: (10000, 32, 32, 3), of float32

讓將模型訓練10個時期,現在與先前的模型相似。

請注意,與之前的模型一樣,使用90%的訓練數據進行訓練,並使用10%的訓練數據進行驗證。驗證集上的性能看起來要好得多。保存模型,然後檢查測試數據集的性能。

總體而言,f1得分為92%,比第一個模型更好!大多數教程都將在這裡結束,但是,可以說教程將在這裡開始,因為啟用模型服務所需的步驟從現在開始!

TensorFlow服務的保存模型

已經在模型服務方法論中對此進行了簡短的討論。要使用TensorFlow Serving服務模型,需要將其保存為SavedModel 格式。多虧了非常漂亮的tf.saved_model.simple_save(…)功能,可以在幾行之內做到這一點。

在繼續設置TensorFlow Serving之前,可以利用TensorFlow的SavedModel命令行介面(CLI)工具saved_model_cli,該工具對於快速檢查模型的輸入和輸出規格很有用。

上面的輸出顯示了與第二種模型有關的詳細資訊,包括輸入和輸出規範。

通過CPU推論服務模型

在本部分中,將展示如何利用TensorFlow服務來利用CPU服務已保存的模型。將在系統中進行本地安裝,但是建議您使用基於Docker安裝的 TF Serving 安裝程式,該安裝程式更易於使用和維護,因為只需使用以下命令拉入容器即可,而無需設置任何配置或依賴項。

docker pull tensorflow/serving

但是,為了在此處顯示不同的選項,還將顯示如何在本地設置TF服務。

安裝TensorFlow服務

在這裡,展示了在本地安裝TF Serving的必要步驟。請注意,這僅包含CPU版本。首先,添加源以獲得TF服務。

!echo "deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal"   | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list &&   curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg   | sudo apt-key add -

接下來,可以使用以下命令刪除TF服務的現有版本(如果存在)。

!sudo apt-get -y remove tensorflow-model-server  Reading package lists... Done  Building dependency tree  Reading state information... Done  The following packages will be REMOVED:    tensorflow-model-server  0 upgraded, 0 newly installed, 1 to remove and 39 not upgraded.  After this operation, 0 B of additional disk space will be used.  (Reading database ... 124893 files and directories currently installed.)  Removing tensorflow-model-server (1.13.0) ...

接下來,使用以下命令安裝TF Serving

!sudo apt-get update && sudo apt-get install tensorflow-model-server  Hit:1 http://packages.cloud.google.com/apt cloud-sdk-stretch InRelease  Get:2 http://security.debian.org stretch/updates InRelease  ...  ...  Preparing to unpack .../tensorflow-model-server_1.14.0_all.deb  Unpacking tensorflow-model-server (1.14.0) ...  Setting up tensorflow-model-server (1.14.0) ...

使用TensorFlow服務開始服務模型

現在,準備開始使用TF Serving服務模型。如果要自定義要提供的模型數量和其他高級配置,需要設置一個模型服務配置文件。配置文件很簡單,並存儲在中的以下程式碼段中進行了描述models.conf。請注意,要同時服務於兩個模型,因此config文件使事情變得更容易。

model_config_list: {    config: {      name:  "fashion_model_serving",      base_path:  "/home/jupyter/tensorflow_serving/tf_saved_models",      model_platform: "tensorflow",      model_version_policy {        specific {          versions: 1          versions: 2        }      }    }  }

可以直接在Jupyter Notebooks中運行以下程式碼以將伺服器作為後台進程啟動,也可以從終端運行它。

根據伺服器日誌消息,可以看到伺服器已成功載入了兩個模型,並且已經準備好提供服務。

服務模型推斷請求

現在模型已經可以提供服務了,首先從使用第一個模型(基本的CNN)提供模型推斷請求開始。

看起來TF Serving能夠正確地服務於模型推斷請求!請注意,在將請求發送到伺服器之前,必須預處理影像並創建適當的有效負載。

看一下使用第二個模型ResNet-50 CNN為相同影像樣本提供模型推理請求的情況。

看起來模型正在處理請求,並且預測比先前的模型要好!

模型預熱

在生產和提供模型時,需要記住的重要一點是,TensorFlow運行時具有延遲初始化的組件,這可能導致載入後發送給模型的第一個請求的延遲較高。此延遲可能比單個推理請求的延遲高几個數量級。因此,最好在載入模型後通過發送一些樣本記錄作為初始請求來預熱模型。可以在模型載入時通過查看以下文檔來執行此操作。

在這裡,將採用一種簡單的方法,將示例請求發送到每個模型,以在載入後對其進行預熱。為此,將一些示例數據保存在一個文件中,可以載入該文件並稍後將其用於熱身模型,如以下程式碼所示。

Model 1 warmup complete

Model 2 warmup complete

基準化模型服務請求

看一下為一堆影像提供模型推理請求需要多長時間。為此,將考慮測試數據集中的10000張影像。請注意,僅發送單個請求,並查看整個批次的推理時間。將在下一部分中查看多個請求。看一下第一個模型的性能。

CPU times: user 7.64 s, sys: 612 ms, total: 8.26 s

Wall time: 9.76 s

Out[116]: 10000

能夠在9.8秒左右的時間內完成10000張影像的推理請求,考慮到模型使用CPU進行推理,這是相當不錯的。現在檢查第二個模型的性能。

CPU times: user 21.6 s, sys: 1.38 s, total: 23 s

Wall time: 36.4 s

Out[122]: 10000

考慮到CPU推斷,服務請求的時間為36秒,還不錯!

使用GPU推論服務模型

在本部分中,將展示如何利用TensorFlow服務來利用GPU服務已保存的模型。這個想法是,如果有GPU,請使用它!將利用Docker來設置TensorFlow Serving系統。

提取TF服務GPU影像

假設已在系統或雲中安裝了docker。可以使用以下程式碼在GPU上獲取最新版本的TF服務

!docker pull tensorflow/serving:latest-gpu  latest-gpu: Pulling from tensorflow/serving  Digest: sha256:fd54edb56a7b  Status: Image is up to date for tensorflow/serving:latest-gpu  docker.io/tensorflow/serving:latest-gpu

可以使用以下命令檢查系統中是否存在映像

!docker images

使用Docker TensorFlow服務GPU開始服務模型

現在,準備開始使用TF Serving服務模型。將通過運行剛剛下載的docker鏡像來做到這一點。實際上,最好從終端運行它。

然後,可以在Docker中使用以下命令來檢查容器是否已啟動並正在運行。

!docker ps -all

最後,可以檢查Docker中的日誌以驗證一切工作正常。

!docker logs 7d4b091ccefa | tail -n 15

這證實了TF Serving將使用系統上的GPU進行推理的事實!

模型熱身

可以利用之前實現的程式碼來預熱我們的模型。在這裡,將重點放在複雜的第二CNN模型上,因此對模型2進行了預熱。

Model 2 warmup complete

基準化模型服務請求

讓獲取所有10000張測試影像,並發送一個請求以使用GPU檢查模型服務時間以進行推理。請注意,此處僅關注第二模型。

CPU times: user 23.5 s, sys: 1.87 s, total: 25.3 s

Wall time: 31.3 s

Out[155]: 10000

10000張影像的總推理時間超過30秒,相當不錯!現在執行一個真實的基準測試。考慮每次要分類的單個服裝影像的10000個獨立請求。TF Serving處理這10000個請求需要多少時間?

100%|██████████| 10000/10000 [01:55<00:00, 86.56it/s]

CPU times: user 39.1 s, sys: 2.2 s, total: 41.3 s

Wall time: 1min 55s

Out[157]: 10000

它需要一個總的115秒服務10000個請求。這意味著TF服務大約在11.5毫秒內滿足每個請求。非常好!

現在嘗試一個有趣的比較。將使用來自的常規model.predict(…)API調用tf.keras來查看處理10000個請求所需的時間。

100%|██████████| 10000/10000 [03:04 <00:00,54.12it / s]

CPU時間:用戶3min 8s,sys:17.2 s,總計:3min 25s

掛牆時間:3min 4s

Out [159]:10000

處理10000個請求總共需要184秒。這意味著使用本機模型預測API,能夠在大約18.4毫秒內滿足每個請求。

這展示了利用TF服務的需求和重要性,尤其是在生產模型時!

獎勵:使用Flask和TensorFlow服務構建服裝分類器API

TF服務非常有用,它提供了一個高性能的系統來滿足推理請求。考慮到端到端的觀點,可能已經注意到模型服務不只是將一些數據作為請求轉儲到伺服器。需要訪問影像數據,對其進行預處理,然後以適當的格式將其發送到TF服務。同樣,一旦獲得響應,就需要訪問類別概率,獲取具有最大概率的類別,然後獲取相應的服裝類別標籤。

整合所有這些步驟的最佳方法是利用Flask之類的健壯框架在TF Serving之上構建一個Web服務/ API,以接受來自現實世界的影像,執行必要的預處理,調用TF Serving,處理響應,然後將最終的JSON響應發送給最終用戶。做筆記,甚至可以dockerize和部署Kubernetes的瓶API或使用WSGI伺服器像Gunicorn規模並提高性能。

使用Flask創建API

將首先使用Flask創建自己的服裝API,將在GitHub存儲庫中找到程式碼文件,但是為了完整和易於理解,還將在此處介紹程式碼。

https://github.com/dipanjanS/data_science_for_all/tree/master/gde_tf_serve_vision/tensorflow_serving

將此文件存儲app.py在伺服器中,該文件構成了API的基礎。

啟動用於TF服務的Docker容器

接下來,檢查並重新啟動用於TF服務的Docker容器(如果尚未啟動並運行)。

!docker start 7d4b091ccefa

!docker ps -all

啟動服裝分類器Web服務

現在,需要啟動Web服務。在生產中,建議不要使用Flask提供的默認Web伺服器,而應使用像Gunicorn一樣更好的生產就緒WSGI伺服器。從終端使用以下命令啟動Web服務。

根據需要利用多名員工來滿足更多請求。現在,使用活動性測試端點檢查API是否處於活動狀態。

(200, 'API Live!')

使用Web服務提供服裝樣本分類

現在,獲取一個樣本真實世界影像,並嘗試使用Web服務執行分類。該影像用以下程式碼表示。

plt.imshow(cv2.cvtColor(cv2.imread('sneaker.jpg'),                          cv2.COLOR_BGR2RGB))

因此,這顯然是運動鞋的形象。利用API來服務於模型預測。請記住,將任何輸入影像編碼為Base64格式,然後對其進行解碼,並在執行模型推斷之前在伺服器端對其進行預處理。

{'apparel_type': 'Sneaker'}

最終,以JSON響應的形式獲得了正確的服裝類別。事情正在按照想要的方式進行!

對Web服務進行基準測試

考慮到Web伺服器的延遲,影像處理,模型推斷和服務,看看現在處理10000個請求要花費多少時間。

100%|██████████| 10000/10000 [05:26<00:00, 30.66it/s]

CPU times: user 1min, sys: 3.17 s, total: 1min 4s

Wall time: 5min 26s

Out [58]: 10000

Inference time per image: 32.599999999999994 ms

能夠在32.6毫秒內滿足每個請求,這還不錯!

結論

希望這篇篇幅冗長而又全面的文章能使對筆記型電腦上的模型構建和原型設計與實際生產模型有很大不同。即使訓練模型,也要始終想一想完整的端到端圖片。一旦訓練好模型,這將幫助更快地設想和實現自己的推理系統。希望這也能帶來一個想法,儘管TensorFlow Serving可能看起來很複雜,但是一旦開始使用它,就可以輕鬆地訓練,保存和提供模型,並且可以與Docker,Flask,Kubernetes等框架很好地兼容。

本文中使用的所有程式碼都可以在GitHub和Jupyter Notebook和必要的文件資產。

https://github.com/dipanjanS

https://github.com/dipanjanS/data_science_for_all/tree/master/gde_tf_serve_vision/tensorflow_serving

推薦閱讀

如何為Tensorflow構建自定義數據集

點擊「閱讀原文」圖書配套資源