用 TFserving 部署深度學習模型

2021-03-02 Python中文社區
個人簡介:wedo實驗君, 數據分析師;熱愛生活,熱愛寫作1.什麼是TFserving

當你訓好你的模型,需要提供給外部使用的時候,你就需要把模型部署到線上,並提供合適的接口給外部調用。你可能會考慮一些問題:

目前流行的深度學習框架Tensorflow和Pytorch, Pytorch官方並沒有提供合適的線上部署方案;Tensorflow則提供了TFserving方案來部署線上模型推理。另外,Model Server for Apache MXNet 為MXNet模型提供推理服務。

本文為TFServing的使用指南。如果你是pytorch或者MXNet模型,也可以通過ONNX轉成TFserving的模型,部署在TFServing上。

那什麼是TFserving?

TFserving是Google 2017推出的線上推理服務;採用C/S架構,客戶端可通過gRPC和RESTfull API與模型服務進行通信。

TFServing的特點:

支持模型版本控制和回滾:Manager會進行模型的版本的管理支持熱更新:Source加載本地模型,通知Manager有新的模型需要加載,Manager檢查模型的版本,通知Source創建的Loader進行加載模型2.TFserving安裝

強烈建議採用docker方式安裝TFserving,安裝依賴docker和nvidia-docker(TFserving的gpu需要)

#安裝yum-utils工具和device-mapper相關依賴包
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2

#添加docker-ce stable版本的倉庫
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

#更新yum緩存文件
yum makecache fast

#查看所有可安裝的docker-ce版本
yum list docker-ce --showduplicates | sort -r

# 安裝docker-ce
yum install docker-ce-17.12.1.ce-1.el7.centos

#允許開機啟動docker-ce服務
systemctl enable docker.service

#啟動Docker-ce服務
systemctl start docker

#運行測試容器hello-world
docker run --rm hello-world

# 安裝nvidia-docker2
yum install -y nvidia-docker2-2.0.3-1.docker17.12.1.ce

# 重啟docker服務
service docker restart

docker pull tensorflow/serving:latest-gpu
# 可以選擇其他版本如 docker pull tensorflow/serving:1.14.0-rc0-gpu

注意:docker版本和nvidia-docker要匹配

目前最新的nvidia-docker需要Docker為19.03 可參考官方https://github.com/NVIDIA/nvidia-dockernvidia-docker2 支持Docker版本低於19.03的其他版本(需>=1.12),現有伺服器有18.09,1.17,1.13  https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-2.0)3.TFserving使用說明3.1 模型轉換

TFserving的模型需要轉換成TFserving的格式, 不支持通常的checkpoint和pb格式。

TFserving的模型包含一個.pb文件和variables目錄(可以為空),導出格式如下:

.
├── 1
│   ├── saved_model.pb
│   └── variables
├── 2
│   ├── saved_model.pb
│   └── variables

不同的深度學習框架的轉換路徑:

(1) pytorch(.pth)--> onnx(.onnx)--> tensorflow(.pb) --> TFserving
(2) keras(.h5)--> tensorflow(.pb) --> TFserving
(3) tensorflow(.pb) --> TFserving

這裡詳細介紹下pb轉換成TFserving模型

import tensorflow as tf
def create_graph(pb_file):
    """Creates a graph from saved GraphDef file and returns a saver."""
    # Creates graph from saved graph_def.pb.
    with tf.gfile.FastGFile(pb_file, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        _ = tf.import_graph_def(graph_def, name='')
def pb_to_tfserving(pb_file, export_path, pb_io_name=[], input_node_name='input', output_node_name='output', signature_name='default_tfserving'):
    # pb_io_name 為 pb模型輸入和輸出的節點名稱,
    # input_node_name為轉化後輸入名
    # output_node_name為轉化後輸出名
    # signature_name 為籤名
    create_graph(pb_file)
    # tensor_name_list = [tensor.name for tensor in tf.get_default_graph().as_graph_def().node]
    input_name = '%s:0' % pb_io_name[0]
    output_name = '%s:0' % pb_io_name[1]
    with tf.Session() as sess:
        in_tensor = sess.graph.get_tensor_by_name(input_name)
        out_tensor = sess.graph.get_tensor_by_name(output_name)
        builder = tf.saved_model.builder.SavedModelBuilder(export_path)  ## export_path導出路徑
        inputs = {input_node_name: tf.saved_model.utils.build_tensor_info(in_tensor)}  
        outputs = {output_node_name: tf.saved_model.utils.build_tensor_info(out_tensor)}
        signature = tf.saved_model.signature_def_utils.build_signature_def(
            inputs, outputs, method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME)
        builder.add_meta_graph_and_variables(
            sess=sess, tags=[tf.saved_model.tag_constants.SERVING],
            signature_def_map={signature_name: signature}, clear_devices=True)  ## signature_name為籤名,可自定義
        builder.save()
 
 
pb_model_path = 'test.pb'
pb_to_tfserving(pb_model_path, './1', pb_io_name=['input_1_1','output_1'],signature_name='your_model')

3.2 TFserving配置和啟動

模型導出後,同一個模型可以導出不同的版本(版本後數字),可以TFserving配置中指定模型和指定版本。TFserving的模型是通過模型名稱和籤名來唯一定位。TFserving 可以配置多個模型,充分利用GPU資源。

# models.config
model_config_list {
  config {
    name: 'your_model'
    base_path: '/models/your_model/'
    model_platform: 'tensorflow'
#     model_version_policy {
#       specific {
#         versions: 42
#         versions: 43
#       }
#     }
#     version_labels {
#       key: 'stable'
#       value: 43
#     }
#     version_labels {
#       key: 'canary'
#       value: 43
#     }
  }
  config {
    name: "mnist",
    base_path: "/models/mnist",
    model_platform: "tensorflow",
    model_version_policy: {
       specific: {
        versions: 1,
        versions: 2
       }
  }
}
 
# 可以通過model_version_policy 進行版本的控制

# 建議把模型和配置文件放在docker外的本地路徑,如/home/tfserving/models, 通過-v 掛載到docker內部
# --model_config_file: 指定模型配置文件
# -e NVIDIA_VISIBLE_DEVICES=0: 指定GPU
# -p 指定埠映射 8500為gRpc 8501為restful api埠
# -t 為docker鏡像
nvidia-docker run  -it --privileged  -d -e NVIDIA_VISIBLE_DEVICES=0  -v /home/tfserving/models:/models  -p 8500:8500 -p 8501:8501 \
 -t tensorflow/serving:latest-gpu \
--model_config_file=/models/models.config
 
# /home/tfserving/models 結構
.
├── models.config
└── your_model
    ├── 1
    │   ├── saved_model.pb
    │   └── variables
    └── 2
        ├── saved_model.pb
        └── variables
 
# test
curl http://192.168.0.3:8501/v1/models/your_model
{
    "model_version_status": [
        {
            "version": "2",
            "state": "AVAILABLE",
            "status": {
            "error_code": "OK",
            "error_message": ""
            }
        }
    ]      
}
 
 
# 其他啟動方式
# 如果多個模型在不同的目錄,可以通過-mount 單獨加載
 
nvidia-docker run  -it --privileged  -d -e NVIDIA_VISIBLE_DEVICES=0 \
--mount type=bind,source=/home/tfserving/models/your_model,target=/models/your_model \
--mount type=bind,source=/home/tfserving/models/your_model/models.config,target=/models/models.config \
-p 8510:8500 -p 8501:8501 \
-t tensorflow/serving:latest-gpu \
--model_config_file=/models/models.config

3.3 TFserving服務調用

客戶端可以通過gRpc和http方式調用TFserving服務模型,支持多種客戶端語言,這裡提供python的調用方式; 調用都是通過模型名稱和籤名來唯一對應一個模型

#
# -*-coding:utf-8 -*-
import tensorflow as tf
from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
import grpc
import time
import numpy as np
import cv2
 
 
class YourModel(object):
    def __init__(self, socket):
        """
 
        Args:
            socket: host and port of the tfserving, like 192.168.0.3:8500
        """
        self.socket = socket
        start = time.time()
        self.request, self.stub = self.__get_request()
        end = time.time()
        print('initialize cost time: ' + str(end - start) + ' s')
 
    def __get_request(self):
        channel = grpc.insecure_channel(self.socket, options=[('grpc.max_send_message_length', 1024 * 1024 * 1024),
                                                              ('grpc.max_receive_message_length', 1024 * 1024 * 1024)]) # 可設置大小
        stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
        request = predict_pb2.PredictRequest()
 
        request.model_spec.name = "your_model"  # model name
        request.model_spec.signature_name = "your_model"  # model signature name
 
        return request, stub
 
    def run(self, image):
        """
 
        Args:
            image: the input image(rgb format)
 
        Returns: embedding is output of model
 
        """
        img = image[..., ::-1] 
        self.request.inputs['input'].CopyFrom(tf.contrib.util.make_tensor_proto(img))  # images is input of model
        result = self.stub.Predict(self.request, 30.0)
        return tf.make_ndarray(result.outputs['output'])
 
    def run_file(self, image_file):
        """
 
        Args:
            image_file: the input image file
 
        Returns:
 
        """
        image = cv2.imread(image_file)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        return self.run(image)
 
 
if __name__ == '__main__':
    model = YourModel('192.168.0.3:8500')
    test_file = './test.jpg'
    result = model.run_file(test_file)
    print(result)
    # [8.014745e-05 9.999199e-01]

restful api調用: restful埠是8501
import cv2
import requests
class SelfEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        elif isinstance(obj, np.floating):
            return float(obj)
        elif isinstance(obj, bytes):
            return str(obj, encoding='utf-8');
        return json.JSONEncoder.default(self, obj)
 
image_file = '/home/tfserving/test.jpg'
image = cv2.imread(image_file)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
img = image[..., ::-1]

 
input_data = {
    "signature_name": "your_model",
    "instances": img
}
data = json.dumps(input_data, cls=SelfEncoder, indent=None)
result = requests.post("http://192.168.0.3:8501/v1/models/your_model:predict", data=data)
eval(result .content)
 
# {'predictions': [8.01474525e-05, 0.999919891]}

5.總結

本文介紹了TFserving部署線上推理服務,從模型的轉換,部署啟動和調用推理,歡迎交流,希望對你有幫助。我們來回答下開篇提出的問題

怎麼提供api接口:TFserving有提供restful api接口,現實部署時會在前面再加一層如flask api

多個模型GPU資源如何分配:TFserving支持部署多模型,通過配置

線上模型如何更新而服務不中斷:TFserving支持模型的不同的版本,如your_model中1和2兩個版本,當你新增一個3模型時,TFserving會自動判斷,自動加載模型3為當前模型,不需要重啟

https://www.tensorflow.org/tfx/guide/servinghttps://www.tensorflow.org/tfx/serving/api_rest

相關焦點

  • 【專利解密】億智電子助力深度學習模型在ASIC上的部署
    作者|嘉德IPR    校對|holly集微網·愛集微APP,各大主流應用商店均可下載【嘉德點評】億智電子的深度學習模型部署專利,通過對量化參數以及格式轉換配置,能夠解決現有技術中深度學習模型無法直接部署到ASIC人工智慧晶片上的問題。
  • 實踐教程|基於 docker 和 Flask 的深度學習模型部署!
    模型部署一直是深度學習算法走向落地的重要的一環。隨著深度學習落地需求越來越迫切,具備一定工程部署能力是算法工程師的必備能力之一。深度學習模型一個比較關鍵的前置條件就是需要花不少時間進行環境配置,可能先需要建一個虛擬環境,然後配置深度學習框架和一些第三方庫,即時性和可移植性都比較差,總體而言可用性就不是那麼強了。那麼有沒有一種可以一鍵部署的方式?能在10分鐘內就可以在一臺新機器上部署好我們的深度學習模型?答案是肯定的。
  • 教程 | 如何使用 Kubernetes 輕鬆部署深度學習模型
    本文展示了如何用 Keras 構建深度學習模型的簡單示例,將其作為一個用 Flask 實現的 REST API,並使用 Docker 和 Kubernetes 進行部署。本文給出的並不是一個魯棒性很好的能夠用於生產的示例,它只是為那些聽說過 Kubernetes 但沒有動手嘗試過的人編寫的快速上手指南。
  • 用Python將Keras深度學習模型部署為Web應用程式
    我們想要的是將深度學習模型部署為世界上任何人都可以訪問的Web應用程式。在本文中,我們將看到如何編寫一個Web應用程式,該應用程式使用經過訓練的Keras遞歸神經網絡,並允許用戶生成新的專利文摘。這個項目建立在遞歸神經網絡的基礎上,但是了解如何創建RNN是不必要的。現在我們將其視為黑匣子:我們按一個開始的順序進行操作,它輸出一個全新的專利文摘,可以在瀏覽器中顯示!
  • 基於 Flask 部署 Keras 深度學習模型
    文 | 風玲兒出處 | 掘金本文主要記錄在進行Flask部署過程中所使用的流程,遇到的問題以及相應的解決方案。1、項目簡介該部分簡要介紹一下前一段時間所做的工作:這是第一次進行深度學習模型的 web 應用部署,在整個過程中,進一步折射出以前知識面之窄,在不斷的入坑、解坑中實現一版。
  • 基於TensorFlow、Docker和Flask部署深度學習模型
    畢業設計期間很多同學不停向我諮詢深度學習在web應用上的實現以及部署問題,特給大家推出如下文章。
  • 深度學習部署
    本文來自visionshop深度學習部署平臺特點:深度學習的兩個方面:部署、訓練面臨的挑戰:現代深度學習部署平臺要求:
  • 加速深度學習在線部署,TensorRT安裝及使用教程
    但在部署推理時,為了降低成本,往往使用單個GPU機器甚至嵌入式平臺(比如 NVIDIA Jetson)進行部署,部署端也要有與訓練時相同的深度學習環境,如caffe,TensorFlow等。由於訓練的網絡模型可能會很大(比如,inception,resnet等),參數很多,而且部署端的機器性能存在差異,就會導致推理速度慢,延遲高。
  • 搭建 Docker Swarm GPU 集群 並 部署 OpenFaas 深度學習模型算法服務
    本周狗哥嘗試在 OpenFaas 框架中加入需要使用 GPU 計算的深度學習模型算法服務,因此需要攻克 Docker 中使用 GPU 資源的問題,經過一周的研究實踐,終於找到了 Docker 使用 Nvidia 顯卡資源的方案,此外還編寫了一個基於 Centos 7 的 OpenFaas Python3-Flask 的 Dockerfile
  • 深度學習算法優化系列二十一 | 在VS2015上利用TensorRT部署YOLOV3-Tiny模型
    前言大家好,最近在VS2015上嘗試用TensorRT來部署檢測模型,中間走了兩天彎路,感覺對於一個完全新手來說要做成功這件事並不會那麼順利。所以這裡寫一篇部署文章,希望能讓使用TensorRT來部署YOLOV3-Tiny檢測模型的同學少走一點彎路。2. 確定走哪條路?
  • 深度學習模型壓縮與加速綜述
    然而,龐大的參數規模帶來的計算開銷、內存需求,使得其在計算能力受限平臺的部署中遇到了巨大的困難與挑戰。因此,如何在不影響深度學習模型性能的情況下進行模型壓縮與加速,成為了學術界和工業界的研究熱點。1、簡介深度學習模型壓縮與加速是指利用神經網絡參數和結構的冗餘性精簡模型,在不影響任務完成度的情況下,得到參數量更少、結構更精簡的模型。被壓縮後的模型對計算資源和內存的需求更小,相比原始模型能滿足更廣泛的應用需求。
  • 如何優化深度學習模型
    深度學習的一個非常重要的步驟是找到正確的超參數,超參數是模型無法學習的。在本文中,我將向你介紹一些最常見的(也是重要的)超參數,這些參數是你抵達Kaggle排行榜#1的必經之路。如果學習率太小,模型將花費太長時間來收斂,如上所述。
  • 教程 | 如何使用Keras、Redis、Flask和Apache把深度學習模型部署到生產環境?
    同時本文還對深度學習 REST API 進行了壓力測試,這種方法可以輕鬆擴展到添加的伺服器。將深度學習模型用遷移到生產是一項不平凡的任務。如果你不相信,請花點時間看看亞馬遜、谷歌、微軟等「科技巨頭」——幾乎所有公司都提供了一些將機器學習/深度學習模型遷移到雲端生產環境中的方法。
  • 深度學習模型壓縮方法
    遷移學習也就是將一個模型的性能遷移到另一個模型上,而對於教師——學生網絡,教師網絡往往是一個更加複雜的網絡,具有非常好的性能和泛化能力,可以用這個網絡來作為一個soft target來指導另外一個更加簡單的學生網絡來學習,使得更加簡單、參數運算量更少的學生模型也能夠具有和教師網絡相近的性能,也算是一種模型壓縮的方式。
  • 深度學習模型真的越大越好嗎?
    AI 前線導讀:今年早些時候,NVIDIA 的研究人員發布了 MegatronLM,這是一個擁有 83 億個參數(比 BERT 大 24 倍)的巨型轉換模型,它在各種語言任務中都取得了最頂尖的性能。雖然這無疑是一項令人印象深刻的技術成就,但我不禁要問:深度學習的方向是否正確?
  • 高效深度學習:讓模型更小、更快、更好!
    >:某些新應用程式提供了現有現成模型可能無法解決的新約束模型爆炸:同一基礎設施(託管)上為不同的應用程式訓練和/或部署多個模型可能最終會耗盡可用資源今天,我們分享一份實用的模型訓練和部署優化指南(高效深度學習),主要關注模型效率問題,包括模型技術、基礎設施和硬體等
  • 輕量級部署,騰訊優圖開源深度學習推理框架TNN
    6 月 10 日,騰訊優圖實驗室宣布正式開源新一代移動端深度學習推理框架 TNN。從學界到工業界,「開源」已經成為 AI 領域的關鍵詞。
  • 【深度】工程師必備—AI模型訓練+推理優化+嵌入部署
    加快梯度下降的收斂速度更有可能獲得一個低模型誤差,或者低泛化誤差的模型降低因未初始化或初始化不當導致的梯度消失或者梯度爆炸問題。此情況會導致模型訓練速度變慢,崩潰,直至失敗。其中隨機初始化,可以打破對稱性,從而保證不同的隱藏單元可以學習到不同的東西3.3 高手也愛的黑科技:訓練被迫中斷怎麼辦,『遷移學習』幫你搞定?
  • OpenCV+深度學習預訓練模型,簡單搞定圖像識別 | 教程
    而OpenCV最近一次版本更新,為我們帶來了更好的深度學習支持,在OpenCV中使用預訓練的深度學習模型變得非常容易。pyimagesearch網站今天發布了一份用OpenCV+深度學習預訓練模型做圖像識別的教程,量子位編譯整理如下:最近,OpenCV 3.3剛剛正式發布,對深度學習(dnn模塊)提供了更好的支持,dnn模塊目前支持Caffe、TensorFlow、Torch、PyTorch等深度學習框架。
  • 【深度學習系列】CNN模型的可視化
    ,熟悉Tensorflow,PaddlePaddle等深度學習框架,負責過多個機器學習落地項目,如垃圾評論自動過濾,用戶分級精準營銷,分布式深度學習平臺搭建等,都取了的不錯的效果。博客專欄:https://www.cnblogs.com/charlotte77/前文傳送門:【好書推薦&學習階段】三個月教你從零入門深度學習【深度學習系列】PaddlePaddle之手寫數字識別【深度學習系列】卷積神經網絡CNN原理詳解(一)——基本原理【深度學習系列】PaddlePaddle之數據預處理