1. 程式人生 > >為你的機器學習模型建立一個API服務

為你的機器學習模型建立一個API服務

1. 什麼是API

當調包俠們訓練好一個模型後,下一步要做的就是與業務開發組同學們進行程式碼對接,以便這些‘AI大腦’們可以順利的被使用。然而往往要面臨不同程式語言的挑戰,例如很常見的是調包俠們用Python訓練模型,開發同學用Java寫業務程式碼,這時候,Api就作為一種解決方案被使用。

簡單地說,API可以看作是顧客與商家之間的聯絡方式。如果顧客以預先定義的格式提供輸入資訊,則商家將獲得顧客的輸入資訊並向其提供結果。

從本質上講,API非常類似於web應用程式,但它沒有提供一個樣式良好的HTML頁面,而是傾向於以標準資料交換格式返回資料,比如JSON、XML等。

接下來讓我們看看如何將機器學習模型(在Python中開發的)封裝為一個API。

首先需要明白什麼是Web服務?Web服務是API的一種形式,只是它假定API駐留在伺服器上,並且可以使用。Web API、Web服務——這些術語通常可以互換使用。

Flask——Python中的Web服務框架。它不是Python中唯一的一個Web框架,其它的例如Django、Falcon、Hug等。Flask框架帶有一個內建的輕量級Web伺服器,它需要最少的配置,因此在本文中將使用Flask框架來開發我們的模型API。

2. 建立一個簡單模型

以一個kaggle經典的比賽專案:泰坦尼克號生還者預測為例,訓練一個簡單的模型。

以下是整個機器學習模型的API程式碼目錄樹:

首先,我們需要匯入訓練集並選擇特徵。因為本文主要是介紹機器學習模型API的編寫,所以模型訓練過程並不做為重點內容,因此我們只選擇其中的'Age', 'Sex', 'Embarked', 'Survived' 這四個特徵來構造訓練集。

import pandas as pd


# 匯入訓練集並選擇特徵
url = "http://s3.amazonaws.com/assets.datacamp.com/course/Kaggle/train.csv"
df = pd.read_csv(url)
include = ['Age', 'Sex', 'Embarked', 'Survived']  
df_ = df[include]

然後,是一個簡單的資料處理過程。

這裡主要是對類別型特徵進行One-hot編碼,對連續型特徵進行空缺值填充。

categoricals = []
for col, col_type in
df_.dtypes.iteritems(): if col_type == 'O': categoricals.append(col) else: df_[col].fillna(0, inplace=True) df_ohe = pd.get_dummies(df_, columns=categoricals, dummy_na=True)

最後,是模型的訓練以及持久化儲存。

模型採用的是邏輯迴歸,使用sklearn.externals.joblib將模型儲存為序列化檔案.pkl。需要注意的是,如果傳入的請求不包含所有可能的category變數值,那麼在預測時,get_dummies()生成的dataframe的列數比訓練得到分類器的列數少,這會導致執行報錯發生。所以在模型訓練期間還需要持久化訓練集One-hot後的列名列表。

from sklearn.linear_model import LogisticRegression
from sklearn.externals import joblib

dependent_variable = 'Survived'
x = df_ohe[df_ohe.columns.difference([dependent_variable])]
y = df_ohe[dependent_variable]
lr = LogisticRegression()
lr.fit(x, y)

# 儲存模型
joblib.dump(lr, 'model.pkl')
print("Model dumped!")

# 把訓練集中的列名儲存為pkl
model_columns = list(x.columns)
joblib.dump(model_columns, 'model_columns.pkl')
print("Models columns dumped!")

到此,我們的model.py的程式碼部分構造完畢。

3. 基於Flask框架建立API服務

使用Flask部署模型服務,需要寫一個函式predict(),並完成以下兩件事:

  1. 當應用程式啟動時,將已持久化的模型載入到記憶體中;
  2. 建立一個API站點,該站點接受輸入變數的請求後,將輸入轉換為適當的格式,並返回預測。

更具體地說,需要API的輸入如下(一個由JSON組成的列表):

[
{"Age": 85, "Sex": "male", "Embarked": "S"},
{"Age": 24, "Sex": '"female"', "Embarked": "C"},
{"Age": 3, "Sex": "male", "Embarked": "C"},
{"Age": 21, "Sex": "male", "Embarked": "S"}
]

而模型API的輸出如下:

{"prediction": [0, 1, 1, 0]}

import traceback
import sys

import pandas as pd
from flask import request
from flask import Flask
from flask import jsonify


app = Flask(__name__)


@app.route('/predict', methods=['POST'])  # Your API endpoint URL would consist /predict
def predict():
    if lr:
        try:
            json_ = request.json
            query = pd.get_dummies(pd.DataFrame(json_))
            query = query.reindex(columns=model_columns, fill_value=0)
            prediction = list(lr.predict(query))
            return jsonify({'prediction': str(prediction)})
        except:
            return jsonify({'trace': traceback.format_exc()})
    else:
        print('Train the model first')
        return 'No model here to use'

我們已經在“/predict”API中包含了所有必需的元素,現在只需編寫主類即可。

from sklearn.externals import joblib

if __name__ == '__main__':

    try:
        port = int(sys.argv[1])  
    except:
        port = 8000  
    lr = joblib.load('model.pkl')  # Load "model.pkl"
    print('Model loaded')
    model_columns = joblib.load('model_columns.pkl')  # Load "model_columns.pkl"
    print('Model columns loaded')
    app.run(host='192.168.100.162', port=port, debug=True)

到此,我們的機器學習模型API已經建立完畢,flask_api.py的程式碼部分也已構造完畢。但在進一步深入之前,讓我們回顧一下之前的所有操作:

  1. 載入了泰坦尼克資料集並選擇了四個特徵。
  2. 進行了必要的資料預處理。
  3. 訓練了一個邏輯迴歸分類器模型並將其序列化。
  4. 持久化訓練集中的列名的列表。
  5. 使用Flask編寫了一個簡單的API,該API通過接收一個由JSON組成的列表,預測一個人是否在沉船中倖存。

4. API的有效性測試

首先執行我們的模型API服務,我們通過Pycharm來啟動上一小節編寫完成的flask_api.py:

可以看到,在啟動API服務後,模型以及列名被順利的載入到了記憶體中。

之後可以通過Postman軟體模擬網頁請求,通過傳遞測試資料來觀察模型API是否能正常返回預測資訊。具體操作如下:

可以看到,模型API順利的接收到了POST請求併發送預測結果。

當然,除了Postman以外,我們也可以編寫Python指令碼request_api.py完成API測試:

import requests

years_exp = [{"Age": 22, "Sex": "male", "Embarked": "S"},
             {"Age": 22, "Sex": "female", "Embarked": "C"},
             {"Age": 80, "Sex": "female", "Embarked": "C"},
             {"Age": 22, "Sex": "male", "Embarked": "S"},
             {"Age": 22, "Sex": "female", "Embarked": "C"},
             {"Age": 80, "Sex": "female", "Embarked": "C"},
             {"Age": 22, "Sex": "male", "Embarked": "S"},
             {"Age": 22, "Sex": "female", "Embarked": "C"},
             {"Age": 80, "Sex": "female", "Embarked": "C"},
             {"Age": 22, "Sex": "male", "Embarked": "S"},
             {"Age": 22, "Sex": "female", "Embarked": "C"},
             {"Age": 80, "Sex": "female", "Embarked": "C"},
             {"Age": 22, "Sex": "male", "Embarked": "S"},
             {"Age": 22, "Sex": "female", "Embarked": "C"},
             {"Age": 80, "Sex": "female", "Embarked": "C"},
             ]
response = requests.post(url='http://192.168.100.162:8000/predict', json=years_exp)
result = response.json()
print('model API返回結果:', result)

同樣我們順利地接收到了模型的返回結果:

 這證明我們的機器學習API已經順利開發完畢,接下來要做的就是交給業務開發組的同學來使用了。

5. 總結

本文介紹瞭如何從機器學習模型構建一個API。儘管這個API很簡單,但描述的還算相對清晰。

此外,除了可以對模型預測部分構建API以外,也可以對訓練過程構建一個API,包括通過傳送超引數、傳送模型型別等讓客戶來構建屬於自己的機器學習模型。當然,這也將是我下一步要做的事情。