个性化阅读
专注于IT技术分析

使用Flask REST API进行Python机器学习预测

本文概述

本文是关于在Flask REST API的机器学习或人工智能(AI)系统中使用Python进行实时预测。此处公开的体系结构可以看作是一种从概念验证(PoC)到适用于机器学习应用程序的最小可行产品(MVP)的方法。

在设计实时解决方案时, Python并不是人们想到的第一选择。但是由于Tensorflow和Scikit-Learn是Python支持的一些最常用的机器学习库, 因此在许多Jupyter Notebook PoC中都可以方便地使用它。

使该解决方案可行的原因是, 与预测相比, 培训要花费大量时间。如果你将培训视为观看电影并预测有关问题的答案的过程, 那么似乎不必在每个新问题之后都重新观看电影, 这是非常有效的。

训练是该”电影”的一种压缩视图, 而预测是从压缩视图中检索信息。无论电影是复杂的还是漫长的, 它都应该非常快。

让我们用Python中的[Flask]快速示例来实现它!

通用机器学习架构

让我们首先概述通用的训练和预测架构流程:

图片替代文字

首先, 创建训练管道以根据目标函数了解过去的数据。

这应该输出两个关键元素:

  1. 特征工程功能:训练时使用的变换应在预测时重用。
  2. 模型参数:应保存最终选择的算法和超参数, 以便可以在预测时重用

请注意, 在训练期间进行的特征工程应仔细保存, 以适用于预测。在此过程中可能会出现的许多其他常见问题是特征缩放, 这是许多算法所必需的。

如果特征X1从值1缩放到1000, 并使用函数f(x)= x / max(X1)重新缩放到[0, 1]范围, 那么如果预测集的值为2000, 会发生什么?

应该事先考虑一些谨慎的调整, 以便映射函数返回一致的输出, 这些输出将在预测时正确计算。

机器学习训练与预测

这里有一个主要问题要解决。我们为什么首先要分开训练和预测?

的确, 在机器学习示例和课程的上下文中, 所有数据都是预先已知的(包括要预测的数据), 构建预测器的一种非常简单的方法是堆叠训练和预测数据(通常称为测试集)。

然后, 有必要在”训练集”上进行训练并在”测试集”上进行预测以获得结果, 同时在训练和测试数据上进行特征工程设计, 在相同且唯一的管道中进行训练和预测。

但是, 在现实生活中, 你通常会拥有训练数据, 并且要预测的数据会在处理过程中输入。换句话说, 你一次看电影, 之后又有一些疑问, 这意味着答案应该简单快捷。

而且, 通常不需要每次输入新数据时都重新训练整个模型, 因为训练需要时间(某些图像集可能需要数周的时间), 并且随着时间的推移应该足够稳定。

这就是为什么在许多系统上可以甚至应该将训练和预测明确分开的原因, 并且这也更好地反映了智能系统(无论是否人工)的学习方式。

过度拟合的连接

训练和预测的分离也是解决过度拟合问题的好方法。

在统计中, 过度拟合是”过于紧密或精确地对应于特定数据集的分析结果, 因此可能无法拟合其他数据或可靠地预测未来的观察结果”。

图片替代文字

绿线表示过拟合模型, 黑线表示正则化模型。绿线最适合训练数据, 但它过于依赖该数据, 与黑线相比, 新看不见的数据有较高的错误率。

过拟合在具有许多特征的数据集中或训练数据有限的数据集中尤为明显。在这两种情况下, 与预测器可以验证的信息相比, 数据都包含太多信息, 并且其中一些甚至可能未链接到预测变量。在这种情况下, 噪声本身可以解释为信号。

控制过度拟合的一种好方法是训练部分数据, 并预测具有基础事实的另一部分。因此, 如果我们训练的数据代表系统的实际情况及其未来状态, 则新数据上的预期误差大致是该数据集上的测量误差。

因此, 如果我们设计正确的训练和预测管道以及正确的数据分割, 那么我们不仅可以解决过度拟合的问题, 而且可以重用该体系结构来预测新数据。

最后一步是控制新数据的错误与预期的相同。总会有一个变化(实际错误始终在预期的误差以下), 并且应该确定什么是可以接受的变化, 但这不是本文的主题。

用于预测的REST API

在那里, 清楚地将训练和预测分开很方便。如果保存了特征工程方法和模型参数, 则可以使用这些元素构建一个简单的REST API。

图片替代文字

这里的关键是在API启动时加载模型和参数。一旦启动并存储在内存中, 每个API调用都会触发功能工程计算和ML算法的”预测”方法。两者通常都足够快以确保实时响应。

可以将API设计为接受要预测的唯一示例或几个不同的示例(批量预测)。

这是实现此原理的最小Python / Flask代码, 带有JSON输入和JSON输出(问题输入, 答案输出):

app = Flask(__name__)

@app.route('/api/makecalc/', methods=['POST'])

def makecalc():

	"""

	Function run at each API call

        No need to re-load the model 

    

	"""

        # reads the received json 

	jsonfile = request.get_json()

	res = dict()

	for key in jsonfile.keys():

            # calculates and predicts 

    	    res[key] = model.predict(doTheCalculation(key))

   	

	# returns a json file 

	return jsonify(res)

if __name__ == '__main__':

        # Model is loaded when the API is launched

	model = pickle.load(open('modelfile', 'rb'))

	app.run(debug=True)

请注意, 该API可用于根据新数据进行预测, 但我不建议你将其用于训练模型。可以使用它, 但是这会使模型训练代码复杂化, 并且对内存资源的要求可能更高。

实施示例-自行车共享

让我们以Kaggle数据集(共享单车)为例。假设我们是一家自行车共享公司, 希望预测每天的自行车租赁数量, 以便更好地管理自行车的维护, 物流和其他业务。

图片替代文字

租金主要取决于天气状况, 因此通过天气预报, 该公司可以在租金达到顶峰时更好地了解情况, 并尽量避免在这些日子进行维护。

首先, 我们训练模型并将其另存为可在Jupyter笔记本中看到的泡菜对象。

这里不处理模型训练和性能, 这只是理解整个过程的一个示例。

然后, 我们编写将在每个API调用中完成的数据转换:

import numpy as np

import pandas as pd

from datetime import date

def doTheCalculation(data):

	data['dayofyear']=(data['dteday']-

    	data['dteday'].apply(lambda x: date(x.year, 1, 1))

    	.astype('datetime64[ns]')).apply(lambda x: x.days)

	X = np.array(data[['instant', 'season', 'yr', 'holiday', 'weekday', 'workingday', 'weathersit', 'temp', 'atemp', 'hum', 'windspeed', 'dayofyear']])

	return X

这只是一个变量(一年中的某天)的计算, 以包括月份和精确的日期。还可以选择列及其要保留的顺序。

然后, 我们需要使用Flask编写REST API:

from flask import Flask, request, redirect, url_for, flash, jsonify

from features_calculation import doTheCalculation

import json, pickle

import pandas as pd

import numpy as np

app = Flask(__name__)

@app.route('/api/makecalc/', methods=['POST'])

def makecalc():

	"""

	Function run at each API call

	"""

	jsonfile = request.get_json()

	data = pd.read_json(json.dumps(jsonfile), orient='index', convert_dates=['dteday'])

	print(data)

	res = dict()

	ypred = model.predict(doTheCalculation(data))

	for i in range(len(ypred)):

    	    res[i] = ypred[i]

    

	return jsonify(res) 

if __name__ == '__main__':

	modelfile = 'modelfile.pickle'    

	model = pickle.load(open(modelfile, 'rb'))

	print("loaded OK")

	app.run(debug=True)

运行该程序, 默认情况下它将在端口5000上提供API。

如果我们在本地测试请求, 仍然使用Python:

import requests, json

url = '[http://127.0.0.1:5000/api/makecalc/](http://127.0.0.1:5000/api/makecalc/)'

text = json.dumps({"0":{"instant":1, "dteday":"2011-01-01T00:00:00.000Z", "season":1, "yr":0, "mnth":1, "holiday":0, "weekday":6, "workingday":0, "weathersit":2, "temp":0.344167, "atemp":0.363625, "hum":0.805833, "windspeed":0.160446}, "1":{"instant":2, "dteday":"2011-01-02T00:00:00.000Z", "season":1, "yr":0, "mnth":1, "holiday":0, "weekday":3, "workingday":0, "weathersit":2, "temp":0.363478, "atemp":0.353739, "hum":0.696087, "windspeed":0.248539}, "2":{"instant":3, "dteday":"2011-01-03T00:00:00.000Z", "season":1, "yr":0, "mnth":1, "holiday":0, "weekday":1, "workingday":1, "weathersit":1, "temp":0.196364, "atemp":0.189405, "hum":0.437273, "windspeed":0.248309}})

该请求包含提供给模型的所有信息。因此, 我们的模型将以指定日期的自行车租赁预测作为响应(这里有三个)。

headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'}
r = requests.post(url, data=text, headers=headers)
print(r, r.text)

<Response [200]> {
  "0": 1063, "1": 1028, "2": 1399
}

而已!这项服务可轻松用于任何公司的应用程序, 进行维护计划或使用户了解自行车的流量, 需求和租赁自行车的可用性。

本文总结

许多机器学习系统(尤其是PoC)的主要缺陷是将训练和预测结合在一起。

如果将它们仔细分开, 那么使用MVP可以很容易地对MVP进行实时预测, 而使用Python / Flask则需要相当低的开发成本和工作量, 尤其是对于许多PoC, 它最初是由Scikit-learn, Tensorflow, 或任何其他Python机器学习库。

但是, 这可能不适用于所有应用程序, 特别是功能设计繁重的应用程序, 或者在每次调用时都需要获取最新数据的最接近匹配项的应用程序。

无论如何, 你是否需要一遍又一遍地看电影来回答关于它们的问题?同样的规则适用于机器学习!

赞(0)
未经允许不得转载:srcmini » 使用Flask REST API进行Python机器学习预测

评论 抢沙发

评论前必须登录!