100天搞定機器學習:模型訓練好了,然后呢?


100天搞定機器學習:模型訓練好了,然后呢?

大家好,我是老胡。

許久沒有更新100天搞定機器學習系列了,最近在看一個開源框架,其中有用到 gRPC ,它可以用於機器學習模型的部署,也可用於深度學習框架的開發,本文就當是《100天搞定機器學習》的番外篇吧。

gRPC(Remote Procedure Call)

gRPC 由 Google 開發,是一款語言中立、平台中立、開源的 RPC 框架。
RPC(Remote Procedure Call)即:遠程過程調用,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。使用的時候,客戶端調用server端提供的接口就像是調用本地的函數一樣。

比如:有兩台服務器A,B,一個應用部署在A服務器上,想要調用B服務器上應用提供的函數/方法,由於不在一個內存空間,不能直接調用,需要通過網絡來表達調用的語義和傳達調用的數據。

RPC更像是一種思想或機制,其實現方式有很多,除了gRPC ,還有阿里巴巴的 Dubbo、Facebook 的 Thrift、Twitter 的 Finagle 等。

gRPC 基於以下理念:定義一個服務,指定其能夠被遠程調用的方法(包含參數和返回類型)。在服務端實現這個接口,並運行一個 gRPC 服務器來處理客戶端調用。在客戶端擁有一個存根能夠像服務端一樣的方法。你可以很容易地用 c++ 創建一個 gRPC 服務端,用 Go、Python、Ruby 來創建客戶端。

上圖中的 Protocbuf 是gRPC的數據序列化工具,使用 Protobuf 將數據序列化成二進制的數據流,即可讓用不同語言(proto3支持C++, Java, Python, Go, Ruby, Objective-C, C#)編寫並在不同平台上運行的應用程序交換數據。ps:Protocbuf 也是 Google 開源的。

Protocol Buffer 官方提供了編譯工具來對 proto 文件進行編譯並生成語言相關的代碼文件,可以極大地減少編碼的工作量。對於序列化協議來說,使用方只需要關注業務對象本身,即 idl 定義,序列化和反序列化的代碼只需要通過工具生成即可。

ProtoBuf 協議的工作流程

gRPC 實例詳解——機器學習模型部署

開始實例之前,需要安裝 gRPC 及相關工具

pip install -U grpcio
pip install -U grpcio-tools
pip install -U protobuf

gRPC的使用通常包括如下幾個步驟:

  • 通過protobuf來定義接口和數據類型
  • 編寫gRPC server端代碼
  • 編寫gRPC client端代碼

下面我們就以Iris數據集為例,用 gRPC server端部署一個隨機森林分類器,client 端發起請求預測鳶尾花類型。

0、訓練一個隨機森林分類模型,把訓練好的模型保存為pkl文件。

# train_model.py
from sklearn import datasets
from sklearn.pipeline import Pipeline
import joblib
from sklearn.ensemble import RandomForestClassifier

def main():
    clf = RandomForestClassifier()
    p = Pipeline([('clf', clf)])
    p.fit(X, y)

    filename_p = 'IrisClassifier.pkl'
    joblib.dump(p, filename_p)
    print('Model saved!')


if __name__ == "__main__":
    iris = datasets.load_iris()
    X, y = iris.data, iris.target
    main()

1、通過protobuf定義接口和數據類型

新建一個iris_demo.proto文件

syntax = "proto3";

package iris;

message IrisPredictRequest {// 定義參數1
    float sepal_length = 1;//參數字段1
    float sepal_width = 2;//參數字段2
    float petal_length = 3;//參數字段3
    float petal_width = 4;//參數字段4
}

message IrisPredictResponse {// 定義參數1
    int32 species = 1;
}

service IrisPredictor{// 定義服務
    rpc predict_iris_species(IrisPredictRequest) returns (IrisPredictResponse){} 
}

proto文件格式一般三部分組成,

  • 頭部的syntax 注明版本號為 "proto3",必須寫,沒理由。
  • 中間的 message 定義了predict_iris_species方法的參數IrisPredictRequest和IrisPredictResponse,還有參數字段的類型。
  • 尾部的 service 定義一個服務IrisPredictor,其中包括 1 個predict_iris_species的RPC方法。這里可以定義多個RPC方法,在 message 中定義對應的參數即可。

2、使用gRPC protobuf生成Python的庫函數

python -m grpc_tools.protoc -I=. --python_out=. --grpc_python_out=. ./iris_demo.proto

其中:

-I指定了源文件的路徑

--python_out, 指定 xxx_pb2.py的輸出路徑,如果使用其它語言請使用對應語言的option

--grpc_python_out 指定xxx_pb2_grpc.py文件的輸出路徑

--*.proto是要編譯的proto文件。

運行成功后,會自動生成iris_demo_pb2.py(里面有消息序列化類)和iris_demo_pb2_grpc.py(包含了服務器 Stub 類和客戶端 Stub 類,以及待實現的服務 RPC 接口)。我們無需關心這兩個py文件的細節,只需要直到在服務端和客戶端怎么調用即可。

本例中,我們會用到的方法如下:
xxx_pb2.py
├── xxx_pb2.IrisPredictRequest 用於傳入特征數據
├── xxx_pb2.IrisPredictResponse 用於預測

xxxx_pb2_grpc.py
├── xxx_pb2_grpc.IrisPredictorServicer 服務器 Stub 類
├── xxx_pb2_grpc.IrisPredictorStub 客戶端 Stub 類

3、寫一個服務器

這里的重點是定義 IrisPredictor 類的 predict_iris_species 方法,然后用 iris_demo_pb2_grpc.py 中的 add_IrisPredictorServicer_to_server 方法將 IrisPredictor 添加到 server。serve 函數里定義了 gRPC 的運行方式,使用 4 個 worker 的線程池。

# iris_prediction_server.py
import grpc
from concurrent import futures
import time
import joblib
import iris_demo_pb2
import iris_demo_pb2_grpc
import predict_iris
from sklearn.ensemble import RandomForestClassifier


class IrisPredictor(iris_demo_pb2_grpc.IrisPredictorServicer):

    @classmethod
    def get_trained_model(cls):
        cls._model = joblib.load('IrisClassifier.pkl')
        return cls._model

    def predict_iris_species(self, request, context):
        model = self.__class__.get_trained_model()
        sepal_length = request.sepal_length
        sepal_width = request.sepal_width
        petal_length = request.petal_length
        petal_width = request.petal_width
        result = model.predict(
            [[sepal_length, sepal_width, petal_length, petal_width]])
        response = iris_demo_pb2.IrisPredictResponse(species=result[0])
        return response  # not sure


def run():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
    iris_demo_pb2_grpc.add_IrisPredictorServicer_to_server(
        IrisPredictor(), server)
    server.add_insecure_port('[::]:50055')
    server.start()
    print("grpc server start...")
    print("Listening on port 50055")
    server.wait_for_termination()


if __name__ == '__main__':
    run()

4、寫一個客戶端

客戶端的邏輯更加簡單,連上gRPC服務,然后發起調用。

# iris_prediction_client.py
import grpc
import iris_demo_pb2
import iris_demo_pb2_grpc


def run():
    channel = grpc.insecure_channel('localhost:50055')
    stub = iris_demo_pb2_grpc.IrisPredictorStub(channel)
    request = iris_demo_pb2.IrisPredictRequest(
        sepal_length=6.7,
        sepal_width=3.0,
        petal_length=5.2,
        petal_width=2.3)
    response = stub.predict_iris_species(request)
    print('The prediction is :', response.species)


if __name__ == '__main__':
    run()

5、調用 RPC

先開啟服務端

$ python iris_prediction_server.py 

另起一個terminal執行客戶端代碼,調用gRPC服務,結果如下:

$ python iris_prediction_client.py 

referance

https://grpc.io/
http://doc.oschina.net/
https://zhuanlan.zhihu.com/p/148139089
https://yu-ishikawa.medium.com/machine-learning-as-a-microservice-in-python-16ba4b9ea4ee


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM