数据分析36计(28):Python 使用 Flask+Docker, 100行代码内实现机器学习实时预测​...

本文介绍了如何使用Python的Flask-RESTful构建一个Docker容器内的机器学习实时预测API。通过Dockerfile创建镜像,train.py训练线性判别分析和多层感知器模型,api.py实现REST接口供HTTP请求调用,提供数据查询、预测结果获取及模型评分等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文的想法是快速轻松地构建 Docker 容器,Python 以使用 Flask 实现机器学习模型执行在线预测 API 。我们将使用 Docker 和 Flask-RESTful 实现线性判别分析和多层感知器神经网络模型的实时预测。

项目包括的文件有:Dockerfile,train.py,api.py,requirements.txt, train.csv,test.json。

  • Dockerfile 将被用来构建 Docker 镜像

  • train.py 使用规范化的 EEG 数据训练两个分类模型(线性判别分析和多层感知器神经网络模型)

  • api.py 是将被调用执行使用 REST API 的在线预测接口脚本

  • requirements.txt(flask, flask-restful, joblib)是 Python 依赖

  • train.csv 用于训练模型的数据

  • test.json 是一个 json 文件,包含待预测的数据

Python 构建 Flask-restful API

第一步先思考我们需要构建哪些接口,输入和输出分别是什么。在这个例子里,我们将使用 包含 1300 行,160 列特征的 EGG 数据 test.json 文件。我们想要实现的 API 包括:

  1. 查询数据

请求方式:GET

请求示例:http://0.0.0.0:5000/line/232

参数说明:line, 必须, 行号

返回结果:

{"Line": "232", "# Letter": "4", ...}
  1. 获取预测结果 请求方式:GET

请求示例:http://0.0.0.0:5000/prediction/232

参数说明:line, 必须, 行号

返回结果:

{
  "prediction LDA": "21",
  "prediction Neural Network": 8
}

结果说明:

  • prediction LDA: LDA 模型分类预测结果

  • prediction Neural Network: 神经网络模型预测结果

  1. 获取模型效果评分 请求方式:GET

请求示例:http://0.0.0.0:5000/score

返回结果:

{
  "Score LDA": 0.17846,
  "Score Neural Network": 0.596923 
}

结果说明:

  • Score LDA: LDA 模型评分

  • Score Neural Network: 神经网络模型评分

最后,我们能通过 HTTP 请求来获取结果,该 api.py 文件实现如下:

# We now need the json library so we can load and export json data
import json
import os
import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.neural_network import MLPClassifier
import pandas as pd
from joblib import load
from sklearn import preprocessing

from flask import Flask

# Set environnment variables
MODEL_DIR = os.environ["MODEL_DIR"]
MODEL_FILE_LDA = os.environ["MODEL_FILE_LDA"]
MODEL_FILE_NN = os.environ["MODEL_FILE_NN"]
MODEL_PATH_LDA = os.path.join(MODEL_DIR, MODEL_FILE_LDA)
MODEL_PATH_NN = os.path.join(MODEL_DIR, MODEL_FILE_NN)

# Loading LDA model
print("Loading model from: {}".format(MODEL_PATH_LDA))
inference_lda = load(MODEL_PATH_LDA)

# loading Neural Network model
print("Loading model from: {}".format(MODEL_PATH_NN))
inference_NN = load(MODEL_PATH_NN)

# Creation of the Flask app
app = Flask(__name__)

#API 1
# Flask route so that we can serve HTTP traffic on that route
@app.route('/line/<Line>')
# Get data from json and return the requested row defined by the variable Line
def line(Line):
    with open('./test.json', 'r') as jsonfile:
       file_data = json.loads(jsonfile.read())
    # We can then find the data for the requested row and send it back as json
    return json.dumps(file_data[Line])

#API 2
# Flask route so that we can serve HTTP traffic on that route
@app.route('/prediction/<int:Line>',methods=['POST', 'GET'])
# Return prediction for both Neural Network and LDA inference model with the requested row as input
def prediction(Line):
    data = pd.read_json('./test.json')
    data_test = data.transpose()
    X = data_test.drop(data_test.loc[:, 'Line':'# Letter'].columns, axis = 1)
    X_test = X.iloc[Line,:].values.reshape(1, -1)
    
    clf_lda = load(MODEL_PATH_LDA)
    prediction_lda = clf_lda.predict(X_test)
    
    clf_nn = load(MODEL_PATH_NN)
    prediction_nn = clf_nn.predict(X_test)
    
    return {'prediction LDA': int(prediction_lda), 'prediction Neural Network': int(prediction_nn)}

#API 3
# Flask route so that we can serve HTTP traffic on that route
@app.route('/score',methods=['POST', 'GET'])
# Return classification score for both Neural Network and LDA inference model from the all dataset provided
def score():
    data = pd.read_json('./test.json')
    data_test = data.transpose()
    y_test = data_test['# Letter'].values
    X_test = data_test.drop(data_test.loc[:, 'Line':'# Letter'].columns, axis = 1)
    
    clf_lda = load(MODEL_PATH_LDA)
    score_lda = clf_lda.score(X_test, y_test)
    
    clf_nn = load(MODEL_PATH_NN)
    score_nn = clf_nn.score(X_test, y_test)
    
    return {'Score LDA': score_lda, 'Score Neural Network': score_nn}

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0')

首先,导入依赖的包和相关的环境变量,该环境变量设置在 Dockerfile 文件中。然后载入线性判别分析模型和多层感知器神经网络模型,这两个模型是在 train.py 文件中训练并保存的。最后我们通过 app = Flask(name) 构建 Flask 应用,构建了三个 Flask 路由可以来通过 HTTP 请求访问。

  • http://0.0.0.0:5000/line/250:从 test.json 文件获取数据,返回请求的数据行,本案例中提取第 250 行数据

  • http://0.0.0.0:5000/prediction/51: 返回输入的对应行号数据的模型预测结果,本案例为第 51 行数据的预测结果

  • http://0.0.0.0:5000/score: 返回所有数据测试得到的分类模型评估效果

Flask 路由可以通过修改 URL(http://0.0.0.0:5000) 中的路由变量来请求我们需要的接口数据(/line/,/prediction/<int:Line>,/score)。

机器学习模型

train.py 利用 train.csv 数据训练两个分类模型。该脚本最后保存了两个模型:线性判别分析(clf_lda)和神经网络多层感知器(clf_NN):

import platform; print(platform.platform())
import sys; print("Python", sys.version)
import numpy; print("NumPy", numpy.__version__)
import scipy; print("SciPy", scipy.__version__)

import os
import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.neural_network import MLPClassifier
import pandas as pd
from joblib import dump
from sklearn import preprocessing

def train():

    # Load directory paths for persisting model

    MODEL_DIR = os.environ["MODEL_DIR"]
    MODEL_FILE_LDA = os.environ["MODEL_FILE_LDA"]
    MODEL_FILE_NN = os.environ["MODEL_FILE_NN"]
    MODEL_PATH_LDA = os.path.join(MODEL_DIR, MODEL_FILE_LDA)
    MODEL_PATH_NN = os.path.join(MODEL_DIR, MODEL_FILE_NN)
      
    # Load, read and normalize training data
    training = "./train.csv"
    data_train = pd.read_csv(training)
        
    y_train = data_train['# Letter'].values
    X_train = data_train.drop(data_train.loc[:, 'Line':'# Letter'].columns, axis = 1)

    print("Shape of the training data")
    print(X_train.shape)
    print(y_train.shape)
        
    # Data normalization (0,1)
    X_train = preprocessing.normalize(X_train, norm='l2')
    
    # Models training
    
    # Linear Discrimant Analysis (Default parameters)
    clf_lda = LinearDiscriminantAnalysis()
    clf_lda.fit(X_train, y_train)
    
    # Serialize model
    from joblib import dump
    dump(clf_lda, MODEL_PATH_LDA)
        
    # Neural Networks multi-layer perceptron (MLP) algorithm
    clf_NN = MLPClassifier(solver='adam', activation='relu', alpha=0.0001, hidden_layer_sizes=(500,), random_state=0, max_iter=1000)
    clf_NN.fit(X_train, y_train)
       
    # Serialize model
    from joblib import dump, load
    dump(clf_NN, MODEL_PATH_NN)
        
if __name__ == '__main__':
    train()
构建 Docker 镜像
  1. 先使用 jupyter/scipy-notebook 作为我们的基础镜像

  2. 创建 my-model 文件夹,并设置环境变量,载入训练的模型

  3. 将镜像的依赖文件复制到镜像中,并安装相关包

  4. 我们复制 train.csv, test.json, train.py and api.py 文件到镜像中

  5. 运行 python3 来执行 train.py 文件,该文件将训练模型并保存到之前设置好的环境路径中

FROM jupyter/scipy-notebook

RUN mkdir my-model
ENV MODEL_DIR=/home/jovyan/my-model
ENV MODEL_FILE_LDA=clf_lda.joblib
ENV MODEL_FILE_NN=clf_nn.joblib

COPY requirements.txt ./requirements.txt
RUN pip install -r requirements.txt 

COPY train.csv ./train.csv
COPY test.json ./test.json

COPY train.py ./train.py
COPY api.py ./api.py


RUN python3 train.py

通过以下命令行构建镜像,这里 -f 加文件名表示以当前路径下的 Dockerfile 构建镜像,注意这里文件名参数一定要与你要构建镜像的文件名一致。

docker build -t my-docker-api -f Dockerfile . 

命令行执行后看到以下的输出才表示成功:

运行 Docker 容器

构建好以上的镜像后,我们来基于该镜像启动容器,启动容器后将通过 python3 来执行 api.py 文件:

  • 这里 -it 是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算用 python 执行 api.py 文件并查看返回结果,因此我们需要交互式终端

  • -p 5000:5000:表示映射端口,冒号前为宿主机端口,冒号后为镜像端口

  • my-docker-api:表示以镜像 my-docker-api 启动容器

  • python3 api.py:表示启动容器后,用 python3 执行 api.py 文件

docker run -it -p 5000:5000 my-docker-api python3 api.py

我们可以看到通过访问 http://0.0.0.0:5000/line/232 就可以得到第 232 行数据:

curl http://0.0.0.0:5000/line/232

通过访问 http://0.0.0.0:5000/prediction/232 就可以得到第 232 行数据的预测结果,其中 LDA 模型预测分类结果为 21,而神经网络模型为 8,那么哪个结果更接近真实结果呢?

curl http://0.0.0.0:5000/prediction/232

通过访问 http://0.0.0.0:5000/score 得到两个模型的分类效果,其中 LDA 模型效果指标为 0.178,而神经网络为 0.570,因此神经网络的模型结果更接近真实值。

curl http://0.0.0.0:5000/score  

源码:https://github.com/Serena-TT/DataSciencePipline

选择 E1 即可。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值