热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何在Python中把机器学习模型转成API

作者:SayakPaul编译:Bot设想这么一种情况:你构建了一个非常好的机器学习模型,比方说它可以预测某种交易中是否存在欺诈嫌疑。现在,你的一个朋友正在为某家银行开发Androi

作者:Sayak Paul

编译:Bot

设想这么一种情况:

你构建了一个非常好的机器学习模型,比方说它可以预测某种交易中是否存在欺诈嫌疑。现在,你的一个朋友正在为某家银行开发Android APP,他希望能把你的模型集成到他们的产品里,因为你的模型太实用了,性能也格外出色。

但是,那个Android APP是用JAVA写的,你的模型是用Python写的。怎么办?难道你还要花时间花精力用JAVA重新写一个?

这时候,你就需要一种秘密武器——API。在实践中,上述情况是把机器学习模型转换成API的常见需求之一,这一点非常重要,因为现在各行各业都在寻找可以把技术用于生产、经营的数据科学家。本文将介绍创建API的具体操作,具体来说,它主要涵盖以下内容:

  • 什么是API
  • Flask基础入门
  • 构建机器学习模型
  • 保存机器学习模型:序列化和反序列化
  • 用Flask为模型创建API
  • 在Postman中测试API

什么是API

简单来说,一个API其实就是两个软件之间的(假定)契约,如果面向终端用户的软件能以预定义的格式提供输入,另一个软件就能扩展其功能,并向面向终端用户的软件提供输出结果。——Analytics Vidhya

从本质上讲,API非常类似Web应用程序,但前者往往以标准数据交换格式返回数据(如JSON、XML等)。一旦开发人员拿到了所需的输出,他们就能按照各种需求对它进行设计。现在有很多流行的机器学习API,比如IBM Watson就有以下功能:

  • 机器翻译:将一种语言的文本输入翻译为最终用户的目标语言,支持英语、葡萄牙语、西班牙语和法语。
  • Message Resonance:分析草稿内容,并对它被一个特定的目标受众接受的可能性进行评分。
  • Q&A:直接根据选定和收集到数据正文或“语料库”中的主要数据来源,解释和回答用户问题。
  • User Modeling:使用语言分析从一个人的通信方式中提取一组个性和社会特征。

Google Vision API也是一个很好的例子,它主要面向计算机视觉任务。

基本上,大多数云服务提供商都会提供一系列大型、综合性的API,而以小规模机器学习为重点的企业则提供即用型API。它们都满足了那些没有太多机器学习专业知识背景的开发人员/企业的需求,方便他们在流程和产品套件中部署机器学习技术。

在Web开发中,一些比较流行的机器学习API有DialogFlow、Microsoft的Cognitive Toolkit、TensorFlow.js等。

Flask基础入门

要入门Flask,首先我们得知道什么是Web服务。Web服务是API的一种形式,它假定API通过服务器托管,并且可以被调用。Web API/Web Service——这些术语通常可以互换使用。

Flask是一个用Python编写的轻量级Web服务框架,当然,它不是Python中的唯一框架,同类竞品还有Django、Falcon、Hug等。但本文只介绍如何用Flask创建API。

如果你下载了Anaconda版,里面就已经包含了Flask。如果你想用pip:

pip install flask

你会发现它非常小,这也是它深受Python开发人员喜爱的一个原因。而另一个原因就是Flask框架附带内置的轻量级Web服务器,需要的配置少,而且可以用Python代码直接控制。

下面的代码很好地展示了Flask的简约性。它创建一个简单的Web-API,在接收到特定URL时会生成一个特定的输出。

from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Welcome to machine learning model APIs!"
if __name__ == '__main__':
app.run(debug=True)

运行后,你可以在终端浏览器中输入这个网址,然后观察结果。

《如何在Python中把机器学习模型转成API》

一些要点

  • Jupyter Notebook非常适合处理有关Python、R和markdown的东西。但一旦涉及构建web服务器,它就会出现很多奇怪的bug。所以建议大家最好在Sublime等文本编辑器里编写Flask代码,并从终端/命令提示符运行代码。
  • 千万不要把文件命名为flask.py。
  • 默认情况下,运行Flask的端口号是5000。有时服务器能在这个端口上正常启动,但有时,如果你是在Web浏览器或任何API客户端(如Postman)中用URL启动,它可能会报错,比如下图:

《如何在Python中把机器学习模型转成API》
《如何在Python中把机器学习模型转成API》

  • 根据Flask的提示,这时服务器已经在端口5000上成功启动了,但是当在浏览器中用URL启动时,它没有输出任何内容。因此,这可能是端口号冲突了。在这种情况下,我们可以把默认端口号5000改成所需的端口号,只需输入app.run(debug=True,port=12345)
  • 输入以上代码后,Flask服务器将如下所示:

《如何在Python中把机器学习模型转成API》
《如何在Python中把机器学习模型转成API》

现在我们来看看输入的代码:

  • 创建Flask实例后,Python会自动生成一个name变量。如果这个文件是作为脚本直接用Python运行的,那么这个变量将为“main”;如果是导入文件,那么“name” 的值将是你导入文件的名称。例如,如果你有test.pyrun.py,并且将test.py导入run.py,那么test.py的“name”值就会是test (app = Flask(test))
  • 关于上面hello()的定义,可以用@app.route(“/“)。同时,装饰器route()可以告诉Flask什么URL可以触发定义好的hello()
  • hello()的作用是在使用API时生成输出。在这种情况下,在Web浏览器转到localhost:5000/会产生预期的输出(假设是默认端口)。

如果我们想为机器学习模型创建API,下面是一些需要牢记的东西。

构建机器学习模型

在这里,我们以最常规的Scikit-learn模型为例,介绍一下怎么用Flask学习Scikit-learn模型。首先,我们来回顾一下Scikit-learn的常用模块:

  • 聚类
  • 回归
  • 分类
  • 降维
  • 模型选择
  • 预处理

对于一般数据,我们在进行发送和接收时会涉及将对象转化为便于传输的格式的操作,它们也被称为对象的序列化(serialization)和反序列化(deserialization)。模型和数据很不一样,但Scikit-learn刚好支持对训练模型的序列化和反序列化,这就为我们节省了重新训练模型的时间。通过使用scikit-learn中的模型序列化副本,我们可以编写Flask API。

同时,Scikit-learn模型的一个要求是数据必需采用数字格式,这就是为什么我们需要把数据集里的分类特征转成数字特征0和1。事实上,除了分类,Scikit-learn的sklearn.preprocessing模块还提供诸如LabelEncoderOneHotEncoder等编码方法。

此外,对于数据集里的缺失值,Scikit-learn不能自动填充,而是需要我们自己手动处理,然后再输入模型。缺失值和上面提到的特征编码其实都是数据预处理的重要步骤,它们对构建性能良好的机器学习模型非常重要。

为了方便演示,这里我们以Kaggle上最受欢迎的数据集——泰坦尼克为例进行讲解。这个数据集主要是个分类问题,我们的任务是根据表格数据预测乘客的生存概率。为了进一步简化,我们只用四个变量:age(年龄)、sex(性别)、embarked(登船港口:C=Cherbourg, Q=Queenstown, S=Southampton)和survived。其中survived是个类别标签。

# Import dependencies
import pandas as pd
import numpy as np
# Load the dataset in a dataframe object and include only four features as mentioned
url = "http://s3.amazonaws.com/assets.datacamp.com/course/Kaggle/train.csv"
df = pd.read_csv(url)
include = ['Age', 'Sex', 'Embarked', 'Survived'] # Only four features
df_ = df[include]

“Sex”和“Embarked”是非数字的分类特征,我们需要对它们进行编码;“age”这个特征有不少缺失值,这点可以汇总统计后用中位数或平均数来填充;Scikit-learn不能识别NaN,所以我们还要为此编写一个辅助函数:

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

上面的代码是为数据集填补缺失值。这里需要注意一点,缺失值对模型性能其实很重要,尤其是当空值过多时,我们用单个值填充要非常谨慎,不然很可能会导致很大的偏差。在这个数据集里,因为有缺失值的列是age,所以我们不应该用0填充NaN。

至于把非数字特征转成数字行驶,你可以用One Hot Encoding,也可以用Pandas提供的get_dummies()

df_ohe = pd.get_dummies(df_, columns=categoricals, dummy_na=True)

现在我们已经完成了预处理,可以准备训练机器学习模型了:选择Logistic回归分类器。

from sklearn.linear_model import LogisticRegression
dependent_variable = 'Survived'
x = df_ohe[df_ohe.columns.difference([dependent_variable])]
y = df_ohe[dependent_variable]
lr = LogisticRegression()
lr.fit(x, y)
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
verbose=0, warm_start=False)

有了模型,之后就是保存模型。从技术上讲这里我们应该对模型做序列化,在Python里,这个操作被称为Pickling。

保存机器学习模型:序列化和反序列化

调用sklearn的joblib

from sklearn.externals import joblib
joblib.dump(lr, 'model.pkl')
['model.pkl']

Logistic回归模型现在保持不变,我们可以用一行代码把它加载到内存中,而把模型加载回工作区的操作就是反序列化。

lr = joblib.load('model.pkl')

用Flask为模型创建API

要用Flask为模型创建服务器,我们要做两件事:

  • 当APP启动时把已经存在的模型加载到内存中。
  • 创建一个API断电,它接受输入变量,将它们转换为适当的格式,并返回预测。

更具体地说,当你输入以下内容时:

[
{"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]}

其中0表示遇难,1表示幸存。这里输入格式是JSON,它是最广泛使用的数据交换格式之一。

要做到上述效果,我们需要先编写一个函数predict(),它的目标如前所述:

  • 当APP启动时把已经存在的模型加载到内存中。
  • 创建一个API断电,它接受输入变量,将它们转换为适当的格式,并返回预测。

我们已经演示了如何加载已有模型,之后是根据接收的输入预测人员生存状态:

from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/predict', methods=['POST'])
def predict():
json_ = request.json
query_df = pd.DataFrame(json_)
query = pd.get_dummies(query_df)
prediction = lr.predict(query)
return jsonify({'prediction': list(prediction)})

虽然看起来挺简单,但你可能会在这个步骤遇到一个小问题。

为了让你编写的函数能正常运行,传入请求中必需包含这四个分类变量的所有可能值,这些值可能是实时的,也可能不是。如果传入请求里出现必要值缺失,那么根据当前方法定义的predict()生成的数据列会比分类器里少,模型就会报错。

要解决这个问题,我们需要在模型训练期间把列保留下来,把任何Python对象序列化为.pkl文件。

model_columns = list(x.columns)
joblib.dump(model_columns, 'model_columns.pkl')
['model_columns.pkl']

由于已经保留了列列表,所以你可以在预测时处理缺失值(记得在APP启动前加载模型):

@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': prediction})
except:
return jsonify({'trace': traceback.format_exc()})
else:
print ('Train the model first')
return ('No model here to use')

你已经在“/ predict”API中包含了所有必需元素,现在你只需要编写主类:

if __name__ == '__main__':
try:
port = int(sys.argv[1]) # This is for a command-line argument
except:
port = 12345 # If you don't provide any port then the port will be set to 12345
lr = joblib.load(model_file_name) # Load "model.pkl"
print ('Model loaded')
model_columns = joblib.load(model_columns_file_name) # Load "model_columns.pkl"
print ('Model columns loaded')
app.run(port=port, debug=True)

现在,这个API就全部完成可以托管了。

当然,如果你想把Logistic回归模型代码和Flask API代码分离为单独的.py文件,这其实是一种很好的编程习惯。那么你的model.py代码应该如下所示:

# Import dependencies
import pandas as pd
import numpy as np
# Load the dataset in a dataframe object and include only four features as mentioned
url = "http://s3.amazonaws.com/assets.datacamp.com/course/Kaggle/train.csv"
df = pd.read_csv(url)
include = ['Age', 'Sex', 'Embarked', 'Survived'] # Only four features
df_ = df[include]
# Data Preprocessing
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)
# Logistic Regression classifier
from sklearn.linear_model import LogisticRegression
dependent_variable = 'Survived'
x = df_ohe[df_ohe.columns.difference([dependent_variable])]
y = df_ohe[dependent_variable]
lr = LogisticRegression()
lr.fit(x, y)
# Save your model
from sklearn.externals import joblib
joblib.dump(lr, 'model.pkl')
print("Model dumped!")
# Load the model that you just saved
lr = joblib.load('model.pkl')
# Saving the data columns from training
model_columns = list(x.columns)
joblib.dump(model_columns, 'model_columns.pkl')
print("Models columns dumped!")

api.py则是:

# Dependencies
from flask import Flask, request, jsonify
from sklearn.externals import joblib
import traceback
import pandas as pd
import numpy as np
# Your API definition
app = Flask(__name__)
@app.route('/predict', methods=['POST'])
def predict():
if lr:
try:
json_ = request.json
print(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')
if __name__ == '__main__':
try:
port = int(sys.argv[1]) # This is for a command-line input
except:
port = 12345 # If you don't provide any port the port will be set to 12345
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(port=port, debug=True)

现在,你可以在名为Postman的API客户端中测试此API 。只要确保model.py与api.py在同一个目录下,并确保两者都已在测试前编译好了,如下图所示:

《如何在Python中把机器学习模型转成API》
《如何在Python中把机器学习模型转成API》

如果所有文件都已成功编译,目录结构应该如下图所示:

《如何在Python中把机器学习模型转成API》
《如何在Python中把机器学习模型转成API》

注:IPYNB文件是可选的。

在Postman中测试API

Postman是测试API最好用的工具之一。如果你下载了最新版本,它的界面应该如下所示:

《如何在Python中把机器学习模型转成API》
《如何在Python中把机器学习模型转成API》

成功启动Flask服务器后,你需要在Postman中输入包含正确端口号的正确URL:

《如何在Python中把机器学习模型转成API》
《如何在Python中把机器学习模型转成API》

恭喜!你刚刚构建了第一个机器学习API。这是个可以根据泰坦尼克号乘客age、sex和embarked信息预测他们生存状态的API,现在,你的朋友就能用前端代码调用它,输出神奇的结果。


推荐阅读
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • python限制递归次数(python最大公约数递归)
    本文目录一览:1、python为什么要进行递归限制 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • 本文介绍了JavaScript进化到TypeScript的历史和背景,解释了TypeScript相对于JavaScript的优势和特点。作者分享了自己对TypeScript的观察和认识,并提到了在项目开发中使用TypeScript的好处。最后,作者表示对TypeScript进行尝试和探索的态度。 ... [详细]
  • cs231n Lecture 3 线性分类笔记(一)
    内容列表线性分类器简介线性评分函数阐明线性分类器损失函数多类SVMSoftmax分类器SVM和Softmax的比较基于Web的可交互线性分类器原型小结注:中文翻译 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 安装Tensorflow-GPU文档第一步:通过Anaconda安装python从这个链接https:www.anaconda.comdownload#window ... [详细]
author-avatar
小花姐姐
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有